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

/*
Represents dates from Jan 1 1970 - Jun 6 2149 as days since the Unix epoch.
This format requires 2 bytes (it's a uint16), in contrast to the 16 or 20 byte
representations (on 32 or 64-bit systems, respectively) used by the standard
time package.

Timezone is accounted for when applicable; when converting from standard time
format into a Date, the date relative to the time value's zone is retained.
Times at any point during a given day (relative to timezone) are normalized to
the same date.

Conversely, conversions back to standard time format may be done using the
Local, UTC, and In methods (semantically corresponding to the same-named Time
methods), but with the result normalized to midnight (the beginning of the day)
relative to that timezone.

All functions and methods with the same names as those found in the stdlib time
package have identical semantics in epochdate, with the exception that
epochdate truncates time-of-day information.
*/
package epochdate

import (
	"errors"
	"time"
)

const (
	day     = 60 * 60 * 24
	maxUnix = (1<<16)*day - 1
)

const (
	RFC3339       = "2006-01-02"
	AmericanShort = "1-2-06"
)

var ErrOutOfRange = errors.New("The given date is out of range")

type Date uint16

func Today() Date {
	date, err := NewFromTime(time.Now())
	if err != nil {
		panic(err)
	}
	return date
}

func Parse(layout, value string) (d Date, err error) {
	t, err := time.Parse(layout, value)
	if err == nil {
		d, err = NewFromTime(t)
	}
	return
}

func NewFromTime(t time.Time) (Date, error) {
	s := t.Unix()
	_, offset := t.Zone()
	return NewFromUnix(s + int64(offset))
}

func NewFromDate(year int, month time.Month, day int) (Date, error) {
	return NewFromUnix(time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Unix())
}

// NewFromUnix creates a Date from a Unix timestamp, relative to any location
// Specifically, if you pass in t.Unix(), where t is a time.Time value with a
// non-UTC zone, you may receive an unexpected Date. Unless this behavior is
// specifically desired (returning the date in one location at the given time
// instant in another location), it's best to use epochdate.NewFromTime(t),
// which normalizes the resulting Date value by adjusting for zone offsets.
func NewFromUnix(seconds int64) (d Date, err error) {
	if UnixInRange(seconds) {
		d = Date(seconds / day)
	} else {
		err = ErrOutOfRange
	}
	return
}

// UnixInRange is true if the provided Unix timestamp is in Date's
// representable range. The timestamp is interpreted according to the semantics
// used by NewFromUnix. You probably won't need to use this, since this will
// only return false if NewFromUnix returns an error of ErrOutOfRange.
func UnixInRange(seconds int64) bool {
	return seconds >= 0 && seconds <= maxUnix
}

// Returns an RFC3339/ISO-8601 date string, of the form "2006-01-02".
func (d Date) String() string {
	return d.Format(RFC3339)
}

// Identical to time.Time.Format, except that any time-of-day format specifiers
// will be equivalent to "00:00:00Z".
func (d Date) Format(layout string) string {
	return d.UTC().Format(layout)
}

func (d Date) Date() (year int, month time.Month, day int) {
	return d.UTC().Date()
}

// UTC returns a UTC Time object set to 00:00:00 on the given date
func (d Date) UTC() time.Time {
	return time.Unix(int64(d)*day, 0).UTC()
}

// Local returns a local Time object set to 00:00:00 on the given date
func (d Date) Local() time.Time {
	return d.In(time.Local)
}

// In returns a location-relative Time object set to 00:00:00 on the given date
func (d Date) In(loc *time.Location) time.Time {
	t := time.Unix(int64(d)*day, 0).In(loc)
	_, offset := t.Zone()
	return t.Add(time.Duration(-offset) * time.Second)
}

func (d Date) MarshalJSON() ([]byte, error) {
	return []byte(d.Format(`"` + RFC3339 + `"`)), nil
}

func (d *Date) UnmarshalJSON(data []byte) (err error) {
	*d, err = Parse(`"`+RFC3339+`"`, string(data))
	return
}
<commit_msg>Added AmericanCommon parse/format layout<commit_after>// Copyright 2012 Kevin Gillette. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Represents dates from Jan 1 1970 - Jun 6 2149 as days since the Unix epoch.
This format requires 2 bytes (it's a uint16), in contrast to the 16 or 20 byte
representations (on 32 or 64-bit systems, respectively) used by the standard
time package.

Timezone is accounted for when applicable; when converting from standard time
format into a Date, the date relative to the time value's zone is retained.
Times at any point during a given day (relative to timezone) are normalized to
the same date.

Conversely, conversions back to standard time format may be done using the
Local, UTC, and In methods (semantically corresponding to the same-named Time
methods), but with the result normalized to midnight (the beginning of the day)
relative to that timezone.

All functions and methods with the same names as those found in the stdlib time
package have identical semantics in epochdate, with the exception that
epochdate truncates time-of-day information.
*/
package epochdate

import (
	"errors"
	"time"
)

const (
	day     = 60 * 60 * 24
	maxUnix = (1<<16)*day - 1
)

const (
	RFC3339        = "2006-01-02"
	AmericanShort  = "1-2-06"
	AmericanCommon = "01-02-06"
)

var ErrOutOfRange = errors.New("The given date is out of range")

type Date uint16

func Today() Date {
	date, err := NewFromTime(time.Now())
	if err != nil {
		panic(err)
	}
	return date
}

func Parse(layout, value string) (d Date, err error) {
	t, err := time.Parse(layout, value)
	if err == nil {
		d, err = NewFromTime(t)
	}
	return
}

func NewFromTime(t time.Time) (Date, error) {
	s := t.Unix()
	_, offset := t.Zone()
	return NewFromUnix(s + int64(offset))
}

func NewFromDate(year int, month time.Month, day int) (Date, error) {
	return NewFromUnix(time.Date(year, month, day, 0, 0, 0, 0, time.UTC).Unix())
}

// NewFromUnix creates a Date from a Unix timestamp, relative to any location
// Specifically, if you pass in t.Unix(), where t is a time.Time value with a
// non-UTC zone, you may receive an unexpected Date. Unless this behavior is
// specifically desired (returning the date in one location at the given time
// instant in another location), it's best to use epochdate.NewFromTime(t),
// which normalizes the resulting Date value by adjusting for zone offsets.
func NewFromUnix(seconds int64) (d Date, err error) {
	if UnixInRange(seconds) {
		d = Date(seconds / day)
	} else {
		err = ErrOutOfRange
	}
	return
}

// UnixInRange is true if the provided Unix timestamp is in Date's
// representable range. The timestamp is interpreted according to the semantics
// used by NewFromUnix. You probably won't need to use this, since this will
// only return false if NewFromUnix returns an error of ErrOutOfRange.
func UnixInRange(seconds int64) bool {
	return seconds >= 0 && seconds <= maxUnix
}

// Returns an RFC3339/ISO-8601 date string, of the form "2006-01-02".
func (d Date) String() string {
	return d.Format(RFC3339)
}

// Identical to time.Time.Format, except that any time-of-day format specifiers
// will be equivalent to "00:00:00Z".
func (d Date) Format(layout string) string {
	return d.UTC().Format(layout)
}

func (d Date) Date() (year int, month time.Month, day int) {
	return d.UTC().Date()
}

// UTC returns a UTC Time object set to 00:00:00 on the given date
func (d Date) UTC() time.Time {
	return time.Unix(int64(d)*day, 0).UTC()
}

// Local returns a local Time object set to 00:00:00 on the given date
func (d Date) Local() time.Time {
	return d.In(time.Local)
}

// In returns a location-relative Time object set to 00:00:00 on the given date
func (d Date) In(loc *time.Location) time.Time {
	t := time.Unix(int64(d)*day, 0).In(loc)
	_, offset := t.Zone()
	return t.Add(time.Duration(-offset) * time.Second)
}

func (d Date) MarshalJSON() ([]byte, error) {
	return []byte(d.Format(`"` + RFC3339 + `"`)), nil
}

func (d *Date) UnmarshalJSON(data []byte) (err error) {
	*d, err = Parse(`"`+RFC3339+`"`, string(data))
	return
}
<|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 etcd

import (
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/coreos/etcd/config"
)

const (
	participantMode int64 = iota
	standbyMode
	stopMode
)

type Server struct {
	config       *config.Config
	id           int64
	pubAddr      string
	raftPubAddr  string
	tickDuration time.Duration

	mode atomicInt
	p    *participant
	s    *standby

	client  *v2client
	peerHub *peerHub

	stopped bool
	mu      sync.Mutex
	stopc   chan struct{}
	log     *log.Logger
	http.Handler
}

func New(c *config.Config) (*Server, error) {
	if err := c.Sanitize(); err != nil {
		log.Fatalf("server.new sanitizeErr=\"%v\"\n", err)
	}

	tc := &tls.Config{
		InsecureSkipVerify: true,
	}
	var err error
	if c.PeerTLSInfo().Scheme() == "https" {
		tc, err = c.PeerTLSInfo().ClientConfig()
		if err != nil {
			log.Fatalf("server.new ClientConfigErr=\"%v\"\n", err)
		}
	}

	tr := new(http.Transport)
	tr.TLSClientConfig = tc
	tr.Dial = (&net.Dialer{Timeout: 200 * time.Millisecond}).Dial
	tr.ResponseHeaderTimeout = defaultTickDuration * defaultHeartbeat
	client := &http.Client{Transport: tr}

	s := &Server{
		config:       c,
		id:           genId(),
		pubAddr:      c.Addr,
		raftPubAddr:  c.Peer.Addr,
		tickDuration: defaultTickDuration,

		mode: atomicInt(stopMode),

		client:  newClient(tc),
		peerHub: newPeerHub(client),

		stopc: make(chan struct{}),
	}
	m := http.NewServeMux()
	m.HandleFunc("/", s.requestHandler)
	m.HandleFunc("/version", versionHandler)
	s.Handler = m

	log.Printf("id=%x server.new raftPubAddr=%s\n", s.id, s.raftPubAddr)
	if err = os.MkdirAll(s.config.DataDir, 0700); err != nil {
		if !os.IsExist(err) {
			return nil, err
		}
	}
	return s, nil
}

func (s *Server) SetTick(tick time.Duration) {
	s.tickDuration = tick
	log.Printf("id=%x server.setTick tick=%q\n", s.id, s.tickDuration)
}

// Stop stops the server elegently.
func (s *Server) Stop() {
	if s.mode.Get() == stopMode {
		return
	}
	s.mu.Lock()
	s.stopped = true
	switch s.mode.Get() {
	case participantMode:
		s.p.stop()
	case standbyMode:
		s.s.stop()
	}
	s.mu.Unlock()
	<-s.stopc
	s.client.CloseConnections()
	s.peerHub.stop()
	log.Printf("id=%x server.stop\n", s.id)
}

func (s *Server) requestHandler(w http.ResponseWriter, r *http.Request) {
	switch s.mode.Get() {
	case participantMode:
		s.p.ServeHTTP(w, r)
	case standbyMode:
		s.s.ServeHTTP(w, r)
	default:
		http.NotFound(w, r)
	}
}

func (s *Server) RaftHandler() http.Handler {
	return http.HandlerFunc(s.ServeRaftHTTP)
}

func (s *Server) ServeRaftHTTP(w http.ResponseWriter, r *http.Request) {
	switch s.mode.Get() {
	case participantMode:
		s.p.raftHandler().ServeHTTP(w, r)
	default:
		http.NotFound(w, r)
	}
}

func (s *Server) Run() error {
	var d *discoverer
	var seeds []string
	durl := s.config.Discovery
	if durl != "" {
		u, err := url.Parse(durl)
		if err != nil {
			return fmt.Errorf("bad discovery URL error: %v", err)
		}
		d = newDiscoverer(u, fmt.Sprint(s.id), s.raftPubAddr)
		if seeds, err = d.discover(); err != nil {
			return err
		}
		log.Printf("id=%x server.run source=-discovery seeds=\"%v\"\n", s.id, seeds)
	} else {
		seeds = s.config.Peers
		log.Printf("id=%x server.run source=-peers seeds=\"%v\"\n", s.id, seeds)
	}
	s.peerHub.setSeeds(seeds)

	next := participantMode
	for {
		s.mu.Lock()
		if s.stopped {
			next = stopMode
		}
		switch next {
		case participantMode:
			p, err := newParticipant(s.id, s.pubAddr, s.raftPubAddr, s.config.DataDir, s.client, s.peerHub, s.tickDuration)
			if err != nil {
				log.Printf("id=%x server.run newParicipanteErr=\"%v\"\n", s.id, err)
				return err
			}
			s.p = p
			dStopc := make(chan struct{})
			if d != nil {
				go d.heartbeat(dStopc)
			}
			s.mode.Set(participantMode)
			log.Printf("id=%x server.run mode=participantMode\n", s.id)
			s.mu.Unlock()
			next = s.p.run()
			if d != nil {
				close(dStopc)
			}
		case standbyMode:
			s.s = newStandby(s.client, s.peerHub)
			s.mode.Set(standbyMode)
			log.Printf("id=%x server.run mode=standbyMode\n", s.id)
			s.mu.Unlock()
			next = s.s.run()
		case stopMode:
			s.mode.Set(stopMode)
			log.Printf("id=%x server.run mode=stopMode\n", s.id)
			s.mu.Unlock()
			s.stopc <- struct{}{}
			return nil
		default:
			panic("unsupport mode")
		}
		if next != stopMode {
			s.id = genId()
		}
	}
}

// setId sets the id for the participant. This should only be used for testing.
func (s *Server) setId(id int64) {
	log.Printf("id=%x server.setId oldId=%x\n", id, s.id)
	s.id = id
}
<commit_msg>server: add TLSHandshakeTimeout for peer hub client<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 etcd

import (
	"crypto/tls"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/url"
	"os"
	"sync"
	"time"

	"github.com/coreos/etcd/config"
)

const (
	participantMode int64 = iota
	standbyMode
	stopMode
)

type Server struct {
	config       *config.Config
	id           int64
	pubAddr      string
	raftPubAddr  string
	tickDuration time.Duration

	mode atomicInt
	p    *participant
	s    *standby

	client  *v2client
	peerHub *peerHub

	stopped bool
	mu      sync.Mutex
	stopc   chan struct{}
	log     *log.Logger
	http.Handler
}

func New(c *config.Config) (*Server, error) {
	if err := c.Sanitize(); err != nil {
		log.Fatalf("server.new sanitizeErr=\"%v\"\n", err)
	}

	tc := &tls.Config{
		InsecureSkipVerify: true,
	}
	var err error
	if c.PeerTLSInfo().Scheme() == "https" {
		tc, err = c.PeerTLSInfo().ClientConfig()
		if err != nil {
			log.Fatalf("server.new ClientConfigErr=\"%v\"\n", err)
		}
	}

	tr := new(http.Transport)
	tr.TLSClientConfig = tc
	tr.Dial = (&net.Dialer{Timeout: 200 * time.Millisecond}).Dial
	tr.TLSHandshakeTimeout = 10 * time.Second
	tr.ResponseHeaderTimeout = defaultTickDuration * defaultHeartbeat
	client := &http.Client{Transport: tr}

	s := &Server{
		config:       c,
		id:           genId(),
		pubAddr:      c.Addr,
		raftPubAddr:  c.Peer.Addr,
		tickDuration: defaultTickDuration,

		mode: atomicInt(stopMode),

		client:  newClient(tc),
		peerHub: newPeerHub(client),

		stopc: make(chan struct{}),
	}
	m := http.NewServeMux()
	m.HandleFunc("/", s.requestHandler)
	m.HandleFunc("/version", versionHandler)
	s.Handler = m

	log.Printf("id=%x server.new raftPubAddr=%s\n", s.id, s.raftPubAddr)
	if err = os.MkdirAll(s.config.DataDir, 0700); err != nil {
		if !os.IsExist(err) {
			return nil, err
		}
	}
	return s, nil
}

func (s *Server) SetTick(tick time.Duration) {
	s.tickDuration = tick
	log.Printf("id=%x server.setTick tick=%q\n", s.id, s.tickDuration)
}

// Stop stops the server elegently.
func (s *Server) Stop() {
	if s.mode.Get() == stopMode {
		return
	}
	s.mu.Lock()
	s.stopped = true
	switch s.mode.Get() {
	case participantMode:
		s.p.stop()
	case standbyMode:
		s.s.stop()
	}
	s.mu.Unlock()
	<-s.stopc
	s.client.CloseConnections()
	s.peerHub.stop()
	log.Printf("id=%x server.stop\n", s.id)
}

func (s *Server) requestHandler(w http.ResponseWriter, r *http.Request) {
	switch s.mode.Get() {
	case participantMode:
		s.p.ServeHTTP(w, r)
	case standbyMode:
		s.s.ServeHTTP(w, r)
	default:
		http.NotFound(w, r)
	}
}

func (s *Server) RaftHandler() http.Handler {
	return http.HandlerFunc(s.ServeRaftHTTP)
}

func (s *Server) ServeRaftHTTP(w http.ResponseWriter, r *http.Request) {
	switch s.mode.Get() {
	case participantMode:
		s.p.raftHandler().ServeHTTP(w, r)
	default:
		http.NotFound(w, r)
	}
}

func (s *Server) Run() error {
	var d *discoverer
	var seeds []string
	durl := s.config.Discovery
	if durl != "" {
		u, err := url.Parse(durl)
		if err != nil {
			return fmt.Errorf("bad discovery URL error: %v", err)
		}
		d = newDiscoverer(u, fmt.Sprint(s.id), s.raftPubAddr)
		if seeds, err = d.discover(); err != nil {
			return err
		}
		log.Printf("id=%x server.run source=-discovery seeds=\"%v\"\n", s.id, seeds)
	} else {
		seeds = s.config.Peers
		log.Printf("id=%x server.run source=-peers seeds=\"%v\"\n", s.id, seeds)
	}
	s.peerHub.setSeeds(seeds)

	next := participantMode
	for {
		s.mu.Lock()
		if s.stopped {
			next = stopMode
		}
		switch next {
		case participantMode:
			p, err := newParticipant(s.id, s.pubAddr, s.raftPubAddr, s.config.DataDir, s.client, s.peerHub, s.tickDuration)
			if err != nil {
				log.Printf("id=%x server.run newParicipanteErr=\"%v\"\n", s.id, err)
				return err
			}
			s.p = p
			dStopc := make(chan struct{})
			if d != nil {
				go d.heartbeat(dStopc)
			}
			s.mode.Set(participantMode)
			log.Printf("id=%x server.run mode=participantMode\n", s.id)
			s.mu.Unlock()
			next = s.p.run()
			if d != nil {
				close(dStopc)
			}
		case standbyMode:
			s.s = newStandby(s.client, s.peerHub)
			s.mode.Set(standbyMode)
			log.Printf("id=%x server.run mode=standbyMode\n", s.id)
			s.mu.Unlock()
			next = s.s.run()
		case stopMode:
			s.mode.Set(stopMode)
			log.Printf("id=%x server.run mode=stopMode\n", s.id)
			s.mu.Unlock()
			s.stopc <- struct{}{}
			return nil
		default:
			panic("unsupport mode")
		}
		if next != stopMode {
			s.id = genId()
		}
	}
}

// setId sets the id for the participant. This should only be used for testing.
func (s *Server) setId(id int64) {
	log.Printf("id=%x server.setId oldId=%x\n", id, s.id)
	s.id = id
}
<|endoftext|>


<commit_before>package raymond

import (
	"bytes"
	"testing"
)

type evalTest struct {
	name   string
	input  string
	data   interface{}
	output string
}

var evalTests = []evalTest{
	{"only content", "this is content", nil, "this is content"},
	// @todo Test with a struct for data

	//
	// Next tests come from:
	//   https://github.com/wycats/handlebars.js/blob/master/spec/basic.js
	//

	{"most basic", "{{foo}}", map[string]string{"foo": "foo"}, "foo"},

	{"escaping (1)", "\\{{foo}}", map[string]string{"foo": "food"}, "{{foo}}"},
	{"escaping (2)", "content \\{{foo}}", map[string]string{}, "content {{foo}}"},
	{"escaping (3)", "\\\\{{foo}}", map[string]string{"foo": "food"}, "\\food"},
	{"escaping (4)", "content \\\\{{foo}}", map[string]string{"foo": "food"}, "content \\food"},
	{"escaping (5)", "\\\\ {{foo}}", map[string]string{"foo": "food"}, "\\\\ food"},

	{"compiling with a basic context", "Goodbye\n{{cruel}}\n{{world}}!", map[string]string{"cruel": "cruel", "world": "world"}, "Goodbye\ncruel\nworld!"},

	{"compiling with an undefined context (1)", "Goodbye\n{{cruel}}\n{{world.bar}}!", nil, "Goodbye\n\n!"},
	// {"compiling with an undefined context (2)", "{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", nil, "Goodbye"},

	{"comments (1)", "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!", map[string]string{"cruel": "cruel", "world": "world"}, "Goodbye\ncruel\nworld!"},
	// {"comments (2)", "    {{~! comment ~}}      blah", nil, "blah"},
	// {"comments (3)", "    {{~!-- long-comment --~}}      blah", nil, "blah"},
	// {"comments (4)", "    {{! comment ~}}      blah", nil, "    blah"},
	// {"comments (5)", "    {{!-- long-comment --~}}      blah", nil, "    blah"},
	// {"comments (6)", "    {{~! comment}}      blah", nil, "      blah"},
	// {"comments (7)", "    {{~!-- long-comment --}}      blah", nil, "      blah"},

	{"boolean (1)", "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!", map[string]interface{}{"goodbye": true, "world": "world"}, "GOODBYE cruel world!"},
	{"boolean (2)", "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!", map[string]interface{}{"goodbye": false, "world": "world"}, "cruel world!"},

	{"zeros (1)", "num1: {{num1}}, num2: {{num2}}", map[string]interface{}{"num1": 42, "num2": 0}, "num1: 42, num2: 0"},
	{"zeros (2)", "num: {{.}}", 0, "num: 0"},
	{"zeros (3)", "num: {{num1/num2}}", map[string]map[string]interface{}{"num1": {"num2": 0}}, "num: 0"},

	{"false (1)", "val1: {{val1}}, val2: {{val2}}", map[string]interface{}{"val1": false, "val2": false}, "val1: false, val2: false"},
	{"false (2)", "val: {{.}}", false, "val: false"},
	{"false (3)", "val: {{val1/val2}}", map[string]map[string]interface{}{"val1": {"val2": false}}, "val: false"},
	{"false (4)", "val1: {{{val1}}}, val2: {{{val2}}}", map[string]interface{}{"val1": false, "val2": false}, "val1: false, val2: false"},
	{"false (5)", "val: {{{val1/val2}}}", map[string]map[string]interface{}{"val1": {"val2": false}}, "val: false"},

	{"newlines (1)", "Alan's\nTest", nil, "Alan's\nTest"},
	{"newlines (2)", "Alan's\rTest", nil, "Alan's\rTest"},

	{"escaping text (1)", "Awesome's", map[string]string{}, "Awesome's"},
	{"escaping text (2)", "Awesome\\", map[string]string{}, "Awesome\\"},
	{"escaping text (3)", "Awesome\\\\ foo", map[string]string{}, "Awesome\\\\ foo"},
	{"escaping text (4)", "Awesome {{foo}}", map[string]string{"foo": "\\"}, "Awesome \\"},
	{"escaping text (5)", " ' ' ", map[string]string{}, " ' ' "},

	{"escaping expressions (6)", "{{{awesome}}}", map[string]string{"awesome": "&'\\<>"}, "&'\\<>"},
	{"escaping expressions (7)", "{{&awesome}}", map[string]string{"awesome": "&'\\<>"}, "&'\\<>"},
	// {"escaping expressions (8)", "{{awesome}}", map[string]string{"awesome": "&\"'`\\<>"}, "&"'`\\<>"},
	// {"escaping expressions (9)", "{{awesome}}", map[string]string{"awesome": "Escaped, <b> looks like: <b>"}, "Escaped, <b> looks like: &lt;b&gt;"},

	// @todo "functions returning safestrings shouldn't be escaped"
	// @todo "functions"
	// @todo "pathed functions with context argument"
	// @todo "depthed functions with context argument"
	// @todo "block functions with context argument"
	// @todo "depthed block functions with context argument"
	// @todo "block functions without context argument"
	// @todo "pathed block functions without context argument"
	// @todo "depthed block functions without context argument"

	{"paths with hyphens (1)", "{{foo-bar}}", map[string]string{"foo-bar": "baz"}, "baz"},
	{"paths with hyphens (2)", "{{foo.foo-bar}}", map[string]map[string]string{"foo": {"foo-bar": "baz"}}, "baz"},
	{"paths with hyphens (3)", "{{foo/foo-bar}}", map[string]map[string]string{"foo": {"foo-bar": "baz"}}, "baz"},

	{"nested paths", "Goodbye {{alan/expression}} world!", map[string]map[string]string{"alan": {"expression": "beautiful"}}, "Goodbye beautiful world!"},
	{"nested paths with empty string value", "Goodbye {{alan/expression}} world!", map[string]map[string]string{"alan": {"expression": ""}}, "Goodbye  world!"},

	// {"literal paths (1)", "Goodbye {{[@alan]/expression}} world!", map[string]map[string]string{"@alan": {"expression": "beautiful"}}, "Goodbye beautiful world!', 'Literal paths can be used"},
	// {"literal paths (2)", "Goodbye {{[foo bar]/expression}} world!", map[string]string{"expression": "beautiful"}, "Goodbye beautiful world!', 'Literal paths can be used"},
	// {"literal references", "Goodbye {{[foo bar]}} world!", map[string]string{"foo bar": "beautiful"}, "Goodbye beautiful world!"},

	// @todo "that current context path ({{.}}) doesn't hit helpers"

	{"complex but empty paths (1)", "{{person/name}}", map[string]map[string]interface{}{"person": {"name": nil}}, ""},
	{"complex but empty paths (2)", "{{person/name}}", map[string]map[string]string{"person": {}}, ""},

	// {"this keyword in paths (1)", "{{#goodbyes}}{{this}}{{/goodbyes}}", map[string]interface{}{"goodbyes": []string{"goodbye", "Goodbye", "GOODBYE"}}, "goodbyeGoodbyeGOODBYE"},
	// {"this keyword in paths (2)", "{{#hellos}}{{this/text}}{{/hellos}}", map[string]interface{}{"hellos": []interface{}{map[string]string{"text": "hello"}, map[string]string{"text": "Hello"}, map[string]string{"text": "HELLO"}}}, "helloHelloHELLO"},

	// @todo "{{#hellos}}{{text/this/foo}}{{/hellos}}" should throw error 'Invalid path: text/this'

	// {"this keyword nested inside path' (1)", "{{[this]}}", map[string]string{"this": "bar"}, "bar"},
	// {"this keyword nested inside path' (2)", "{{text/[this]}}", map[string]map[string]string{"text": {"this": "bar"}}, "bar"},

	// @todo {"this keyword in helpers (1)", "{{#goodbyes}}{{foo this}}{{/goodbyes}}", ..., "bar goodbyebar Goodbyebar GOODBYE"},
	// @todo {"this keyword in helpers (2)", "{{#hellos}}{{foo this/text}}{{/hellos}}", ..., "bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths"},

	// @todo "this keyword nested inside helpers param"

	{"pass string literals (1)", `{{"foo"}}`, map[string]string{}, ""},
	{"pass string literals (2)", `{{"foo"}}`, map[string]string{"foo": "bar"}, "bar"},
	{"pass string literals (3)", `{{#"foo"}}{{.}}{{/"foo"}}`, map[string]interface{}{"foo": []string{"bar", "baz"}}, "barbaz"},

	{"pass number literals (1)", "{{12}}", map[string]string{}, ""},
	{"pass number literals (2)", "{{12}}", map[string]string{"12": "bar"}, "bar"},
	{"pass number literals (3)", "{{12.34}}", map[string]string{}, ""},
	{"pass number literals (4)", "{{12.34}}", map[string]string{"12.34": "bar"}, "bar"},
	// @todo {"pass number literals (5)", "{{12.34 1}}", ...function..., "bar1"},

	{"pass boolean literals (1)", "{{true}}", map[string]string{}, ""},
	{"pass boolean literals (2)", "{{true}}", map[string]string{"": "foo"}, ""},
	{"pass boolean literals (3)", "{{false}}", map[string]string{"false": "foo"}, "foo"},

	// @todo "should handle literals in subexpression"

	//
	// @todo Adds tests from:
	//   https://github.com/wycats/handlebars.js/blob/master/spec/blocks.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/builtin.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/data.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/partials.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/regressions.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/strict.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/string-params.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/subexpression.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/whitespace-control.js
	//
	//   https://github.com/wycats/handlebars.js/blob/master/spec/mustache/
	//
}

func TestEval(t *testing.T) {
	for _, test := range evalTests {
		var err error
		var tpl *Template

		buf := new(bytes.Buffer)

		// parse template
		tpl, err = Parse(test.input)
		if err != nil {
			t.Errorf("Test '%s' failed - Failed to parse template\ninput:\n\t'%s'\nerror:\n\t%s", test.name, test.input, err)
		} else {
			// render template
			err = tpl.Exec(buf, test.data)
			if err != nil {
				t.Errorf("Test '%s' failed\ninput:\n\t'%s'\nerror:\n\t%s\nAST:\n\t%s", test.name, test.input, err, tpl.PrintAST())
			} else {
				// check output
				output := buf.String()
				if test.output != output {
					t.Errorf("Test '%s' failed\ninput:\n\t'%s'\nexpected\n\t%q\ngot\n\t%q\nAST:\n\t%s", test.name, test.input, test.output, output, tpl.PrintAST())
				}
			}
		}
	}
}
<commit_msg>Adds a test<commit_after>package raymond

import (
	"bytes"
	"testing"
)

type evalTest struct {
	name   string
	input  string
	data   interface{}
	output string
}

var evalTests = []evalTest{
	{"only content", "this is content", nil, "this is content"},
	// @todo Test with a struct for data

	//
	// Next tests come from:
	//   https://github.com/wycats/handlebars.js/blob/master/spec/basic.js
	//

	{"most basic", "{{foo}}", map[string]string{"foo": "foo"}, "foo"},

	{"escaping (1)", "\\{{foo}}", map[string]string{"foo": "food"}, "{{foo}}"},
	{"escaping (2)", "content \\{{foo}}", map[string]string{}, "content {{foo}}"},
	{"escaping (3)", "\\\\{{foo}}", map[string]string{"foo": "food"}, "\\food"},
	{"escaping (4)", "content \\\\{{foo}}", map[string]string{"foo": "food"}, "content \\food"},
	{"escaping (5)", "\\\\ {{foo}}", map[string]string{"foo": "food"}, "\\\\ food"},

	{"compiling with a basic context", "Goodbye\n{{cruel}}\n{{world}}!", map[string]string{"cruel": "cruel", "world": "world"}, "Goodbye\ncruel\nworld!"},

	{"compiling with an undefined context (1)", "Goodbye\n{{cruel}}\n{{world.bar}}!", nil, "Goodbye\n\n!"},
	{"compiling with an undefined context (2)", "{{#unless foo}}Goodbye{{../test}}{{test2}}{{/unless}}", nil, "Goodbye"},

	{"comments (1)", "{{! Goodbye}}Goodbye\n{{cruel}}\n{{world}}!", map[string]string{"cruel": "cruel", "world": "world"}, "Goodbye\ncruel\nworld!"},
	// {"comments (2)", "    {{~! comment ~}}      blah", nil, "blah"},
	// {"comments (3)", "    {{~!-- long-comment --~}}      blah", nil, "blah"},
	// {"comments (4)", "    {{! comment ~}}      blah", nil, "    blah"},
	// {"comments (5)", "    {{!-- long-comment --~}}      blah", nil, "    blah"},
	// {"comments (6)", "    {{~! comment}}      blah", nil, "      blah"},
	// {"comments (7)", "    {{~!-- long-comment --}}      blah", nil, "      blah"},

	{"boolean (1)", "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!", map[string]interface{}{"goodbye": true, "world": "world"}, "GOODBYE cruel world!"},
	{"boolean (2)", "{{#goodbye}}GOODBYE {{/goodbye}}cruel {{world}}!", map[string]interface{}{"goodbye": false, "world": "world"}, "cruel world!"},

	{"zeros (1)", "num1: {{num1}}, num2: {{num2}}", map[string]interface{}{"num1": 42, "num2": 0}, "num1: 42, num2: 0"},
	{"zeros (2)", "num: {{.}}", 0, "num: 0"},
	{"zeros (3)", "num: {{num1/num2}}", map[string]map[string]interface{}{"num1": {"num2": 0}}, "num: 0"},

	{"false (1)", "val1: {{val1}}, val2: {{val2}}", map[string]interface{}{"val1": false, "val2": false}, "val1: false, val2: false"},
	{"false (2)", "val: {{.}}", false, "val: false"},
	{"false (3)", "val: {{val1/val2}}", map[string]map[string]interface{}{"val1": {"val2": false}}, "val: false"},
	{"false (4)", "val1: {{{val1}}}, val2: {{{val2}}}", map[string]interface{}{"val1": false, "val2": false}, "val1: false, val2: false"},
	{"false (5)", "val: {{{val1/val2}}}", map[string]map[string]interface{}{"val1": {"val2": false}}, "val: false"},

	{"newlines (1)", "Alan's\nTest", nil, "Alan's\nTest"},
	{"newlines (2)", "Alan's\rTest", nil, "Alan's\rTest"},

	{"escaping text (1)", "Awesome's", map[string]string{}, "Awesome's"},
	{"escaping text (2)", "Awesome\\", map[string]string{}, "Awesome\\"},
	{"escaping text (3)", "Awesome\\\\ foo", map[string]string{}, "Awesome\\\\ foo"},
	{"escaping text (4)", "Awesome {{foo}}", map[string]string{"foo": "\\"}, "Awesome \\"},
	{"escaping text (5)", " ' ' ", map[string]string{}, " ' ' "},

	{"escaping expressions (6)", "{{{awesome}}}", map[string]string{"awesome": "&'\\<>"}, "&'\\<>"},
	{"escaping expressions (7)", "{{&awesome}}", map[string]string{"awesome": "&'\\<>"}, "&'\\<>"},
	// {"escaping expressions (8)", "{{awesome}}", map[string]string{"awesome": "&\"'`\\<>"}, "&"'`\\<>"},
	// {"escaping expressions (9)", "{{awesome}}", map[string]string{"awesome": "Escaped, <b> looks like: <b>"}, "Escaped, <b> looks like: &lt;b&gt;"},

	// @todo "functions returning safestrings shouldn't be escaped"
	// @todo "functions"
	// @todo "pathed functions with context argument"
	// @todo "depthed functions with context argument"
	// @todo "block functions with context argument"
	// @todo "depthed block functions with context argument"
	// @todo "block functions without context argument"
	// @todo "pathed block functions without context argument"
	// @todo "depthed block functions without context argument"

	{"paths with hyphens (1)", "{{foo-bar}}", map[string]string{"foo-bar": "baz"}, "baz"},
	{"paths with hyphens (2)", "{{foo.foo-bar}}", map[string]map[string]string{"foo": {"foo-bar": "baz"}}, "baz"},
	{"paths with hyphens (3)", "{{foo/foo-bar}}", map[string]map[string]string{"foo": {"foo-bar": "baz"}}, "baz"},

	{"nested paths", "Goodbye {{alan/expression}} world!", map[string]map[string]string{"alan": {"expression": "beautiful"}}, "Goodbye beautiful world!"},
	{"nested paths with empty string value", "Goodbye {{alan/expression}} world!", map[string]map[string]string{"alan": {"expression": ""}}, "Goodbye  world!"},

	// {"literal paths (1)", "Goodbye {{[@alan]/expression}} world!", map[string]map[string]string{"@alan": {"expression": "beautiful"}}, "Goodbye beautiful world!', 'Literal paths can be used"},
	// {"literal paths (2)", "Goodbye {{[foo bar]/expression}} world!", map[string]string{"expression": "beautiful"}, "Goodbye beautiful world!', 'Literal paths can be used"},
	// {"literal references", "Goodbye {{[foo bar]}} world!", map[string]string{"foo bar": "beautiful"}, "Goodbye beautiful world!"},

	// @todo "that current context path ({{.}}) doesn't hit helpers"

	{"complex but empty paths (1)", "{{person/name}}", map[string]map[string]interface{}{"person": {"name": nil}}, ""},
	{"complex but empty paths (2)", "{{person/name}}", map[string]map[string]string{"person": {}}, ""},

	// {"this keyword in paths (1)", "{{#goodbyes}}{{this}}{{/goodbyes}}", map[string]interface{}{"goodbyes": []string{"goodbye", "Goodbye", "GOODBYE"}}, "goodbyeGoodbyeGOODBYE"},
	// {"this keyword in paths (2)", "{{#hellos}}{{this/text}}{{/hellos}}", map[string]interface{}{"hellos": []interface{}{map[string]string{"text": "hello"}, map[string]string{"text": "Hello"}, map[string]string{"text": "HELLO"}}}, "helloHelloHELLO"},

	// @todo "{{#hellos}}{{text/this/foo}}{{/hellos}}" should throw error 'Invalid path: text/this'

	// {"this keyword nested inside path' (1)", "{{[this]}}", map[string]string{"this": "bar"}, "bar"},
	// {"this keyword nested inside path' (2)", "{{text/[this]}}", map[string]map[string]string{"text": {"this": "bar"}}, "bar"},

	// @todo {"this keyword in helpers (1)", "{{#goodbyes}}{{foo this}}{{/goodbyes}}", ..., "bar goodbyebar Goodbyebar GOODBYE"},
	// @todo {"this keyword in helpers (2)", "{{#hellos}}{{foo this/text}}{{/hellos}}", ..., "bar hellobar Hellobar HELLO', 'This keyword evaluates in more complex paths"},

	// @todo "this keyword nested inside helpers param"

	{"pass string literals (1)", `{{"foo"}}`, map[string]string{}, ""},
	{"pass string literals (2)", `{{"foo"}}`, map[string]string{"foo": "bar"}, "bar"},
	{"pass string literals (3)", `{{#"foo"}}{{.}}{{/"foo"}}`, map[string]interface{}{"foo": []string{"bar", "baz"}}, "barbaz"},

	{"pass number literals (1)", "{{12}}", map[string]string{}, ""},
	{"pass number literals (2)", "{{12}}", map[string]string{"12": "bar"}, "bar"},
	{"pass number literals (3)", "{{12.34}}", map[string]string{}, ""},
	{"pass number literals (4)", "{{12.34}}", map[string]string{"12.34": "bar"}, "bar"},
	// @todo {"pass number literals (5)", "{{12.34 1}}", ...function..., "bar1"},

	{"pass boolean literals (1)", "{{true}}", map[string]string{}, ""},
	{"pass boolean literals (2)", "{{true}}", map[string]string{"": "foo"}, ""},
	{"pass boolean literals (3)", "{{false}}", map[string]string{"false": "foo"}, "foo"},

	// @todo "should handle literals in subexpression"

	//
	// @todo Adds tests from:
	//   https://github.com/wycats/handlebars.js/blob/master/spec/blocks.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/builtin.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/data.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/partials.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/regressions.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/strict.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/string-params.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/subexpression.js
	//   https://github.com/wycats/handlebars.js/blob/master/spec/whitespace-control.js
	//
	//   https://github.com/wycats/handlebars.js/blob/master/spec/mustache/
	//
}

func TestEval(t *testing.T) {
	for _, test := range evalTests {
		var err error
		var tpl *Template

		buf := new(bytes.Buffer)

		// parse template
		tpl, err = Parse(test.input)
		if err != nil {
			t.Errorf("Test '%s' failed - Failed to parse template\ninput:\n\t'%s'\nerror:\n\t%s", test.name, test.input, err)
		} else {
			// render template
			err = tpl.Exec(buf, test.data)
			if err != nil {
				t.Errorf("Test '%s' failed\ninput:\n\t'%s'\nerror:\n\t%s\nAST:\n\t%s", test.name, test.input, err, tpl.PrintAST())
			} else {
				// check output
				output := buf.String()
				if test.output != output {
					t.Errorf("Test '%s' failed\ninput:\n\t'%s'\nexpected\n\t%q\ngot\n\t%q\nAST:\n\t%s", test.name, test.input, test.output, output, tpl.PrintAST())
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"fmt"
	"github.com/tealeg/xlsx"
	"os"
)

type Export struct {
	FromFile     string
	ToFile       string
	StartRow     int
	StartCol     int
	SheetName    string
	FieldNames   []string
	ExcelColumns []string
}

func NewExport(fromfile, tofile, sheetname string) *Export {
	return &Export{
		FromFile:  fromfile,
		ToFile:    tofile,
		SheetName: sheetname,
	}
}

func (export *Export) Export() {

	//Open xlsx file for reading
	xlFile, error := xlsx.OpenFile(export.FromFile)
	if error != nil {
		fmt.Println("File Error:", error)
		return
	}

	sheet := xlFile.Sheet[export.SheetName]
	var table [][]string
	var numberOfCols int
	numberOfCols = 0
	if len(export.FieldNames) > 0 {
		table = append(table, export.FieldNames)
		numberOfCols = len(export.FieldNames)
		if len(export.ExcelColumns) == 0 {
			export.ExcelColumns = make([]string, numberOfCols)
			for n := 0; n < numberOfCols; n++ {
				export.ExcelColumns[n] = xlsx.ColIndexToLetters(n + export.StartCol)
			}
		}
	} else if len(export.ExcelColumns) > 0 {
		numberOfCols = len(export.ExcelColumns)
		export.FieldNames = export.ExcelColumns
	} else {
		numberOfCols = 0
	}
	if len(export.FieldNames) != len(export.ExcelColumns) {
		panic("Field names and excel columns must contain the same number of fields.")
	}
	for rowi, row := range sheet.Rows {
		if rowi < export.StartRow {
			continue
		}

		if numberOfCols == 0 {
			numberOfCols = len(row.Cells)
		}

		if len(row.Cells) > export.StartCol {
			tablerow := make([]string, numberOfCols)
			table = append(table, tablerow)
			// for coli, cell := range row.Cells[export.StartCol : export.StartCol+numberOfCols] {
			// 	tablerow[coli] = cell.Value
			// }
			for coli := 0; coli < numberOfCols; coli++ {
				tablerow[coli] = row.Cells[xlsx.ColLettersToIndex(export.ExcelColumns[coli])].Value
			}
		}
	}

	//Create csv file for export.
	csvfile, err := os.Create(export.ToFile)
	defer csvfile.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	writer := csv.NewWriter(csvfile)
	writer.WriteAll(table)
}
<commit_msg>format time values<commit_after>package main

import (
	"encoding/csv"
	"fmt"
	"github.com/tealeg/xlsx"
	"os"
)

type Export struct {
	FromFile     string
	ToFile       string
	StartRow     int
	StartCol     int
	SheetName    string
	FieldNames   []string
	ExcelColumns []string
}

func NewExport(fromfile, tofile, sheetname string) *Export {
	return &Export{
		FromFile:  fromfile,
		ToFile:    tofile,
		SheetName: sheetname,
	}
}

func (export *Export) Export() {

	//Open xlsx file for reading
	xlFile, error := xlsx.OpenFile(export.FromFile)
	if error != nil {
		fmt.Println("File Error:", error)
		return
	}

	sheet := xlFile.Sheet[export.SheetName]
	var table [][]string
	var numberOfCols int
	numberOfCols = 0
	if len(export.FieldNames) > 0 {
		table = append(table, export.FieldNames)
		numberOfCols = len(export.FieldNames)
		if len(export.ExcelColumns) == 0 {
			export.ExcelColumns = make([]string, numberOfCols)
			for n := 0; n < numberOfCols; n++ {
				export.ExcelColumns[n] = xlsx.ColIndexToLetters(n + export.StartCol)
			}
		}
	} else if len(export.ExcelColumns) > 0 {
		numberOfCols = len(export.ExcelColumns)
		export.FieldNames = export.ExcelColumns
	} else {
		numberOfCols = 0
	}
	if len(export.FieldNames) != len(export.ExcelColumns) {
		panic("Field names and excel columns must contain the same number of fields.")
	}
	for rowi, row := range sheet.Rows {
		if rowi < export.StartRow {
			continue
		}

		if numberOfCols == 0 {
			numberOfCols = len(row.Cells)
		}

		if len(row.Cells) > export.StartCol {
			tablerow := make([]string, numberOfCols)
			table = append(table, tablerow)
			// for coli, cell := range row.Cells[export.StartCol : export.StartCol+numberOfCols] {
			// 	tablerow[coli] = cell.Value
			// }
			for coli := 0; coli < numberOfCols; coli++ {
				cell := row.Cells[xlsx.ColLettersToIndex(export.ExcelColumns[coli])]
				if cell.IsTime() {
					t1, err := cell.GetTime(false)
					if err != nil {
						tablerow[coli] = fmt.Sprint("%s", err)
					} else {
						tablerow[coli] = t1.Format("2006-01-02 15:04")
					}
				} else {
					tablerow[coli] = cell.Value
				}
			}
		}
	}

	//Create csv file for export.
	csvfile, err := os.Create(export.ToFile)
	defer csvfile.Close()
	if err != nil {
		fmt.Println(err)
		return
	}

	writer := csv.NewWriter(csvfile)
	writer.WriteAll(table)
}
<|endoftext|>


<commit_before>package sirius

import (
	"time"
)

type ExtensionRunner interface {
	Run([]Execution, chan<- ExecutionResult, time.Duration)
}

type Execution struct {
	Extension Extension
	Message   Message
	Config    ExtensionConfig
}

type ExecutionResult struct {
	Error  error
	Action MessageAction
}

type AsyncRunner struct {
	Actions chan MessageAction
}

func NewExecution(x Extension, m Message, cfg ExtensionConfig) *Execution {
	return &Execution{
		Extension: x,
		Message:   m,
		Config:    cfg,
	}
}

func NewAsyncRunner() *AsyncRunner {
	return &AsyncRunner{
		Actions: make(chan MessageAction),
	}
}

func (r *AsyncRunner) Run(exe []Execution, res chan<- ExecutionResult, timeout time.Duration) {
	act := make(chan ExecutionResult, len(exe))

	for _, e := range exe {
		r.execute(e, act)
	}

ActionReceive:
	for range exe {
		select {
		case res <- <-act:
		case <-time.After(timeout):
			break ActionReceive
		}
	}

	close(res)
}

func (r *AsyncRunner) execute(e Execution, res chan<- ExecutionResult) {
	go func() {
		err, a := e.Extension.Run(e.Message, e.Config)

		r := ExecutionResult{
			Error: err,
			Action: a,
		}

		res <- r
	}()
}
<commit_msg>Go fmt<commit_after>package sirius

import (
	"time"
)

type ExtensionRunner interface {
	Run([]Execution, chan<- ExecutionResult, time.Duration)
}

type Execution struct {
	Extension Extension
	Message   Message
	Config    ExtensionConfig
}

type ExecutionResult struct {
	Error  error
	Action MessageAction
}

type AsyncRunner struct {
	Actions chan MessageAction
}

func NewExecution(x Extension, m Message, cfg ExtensionConfig) *Execution {
	return &Execution{
		Extension: x,
		Message:   m,
		Config:    cfg,
	}
}

func NewAsyncRunner() *AsyncRunner {
	return &AsyncRunner{
		Actions: make(chan MessageAction),
	}
}

func (r *AsyncRunner) Run(exe []Execution, res chan<- ExecutionResult, timeout time.Duration) {
	act := make(chan ExecutionResult, len(exe))

	for _, e := range exe {
		r.execute(e, act)
	}

ActionReceive:
	for range exe {
		select {
		case res <- <-act:
		case <-time.After(timeout):
			break ActionReceive
		}
	}

	close(res)
}

func (r *AsyncRunner) execute(e Execution, res chan<- ExecutionResult) {
	go func() {
		err, a := e.Extension.Run(e.Message, e.Config)

		r := ExecutionResult{
			Error:  err,
			Action: a,
		}

		res <- r
	}()
}
<|endoftext|>


<commit_before>package v5

import (
	"context"
	"fmt"

	"github.com/golang/glog"

	"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
)

const (
	elasticsearchLocalNodeID = "_local"
)

func (p *Pilot) syncFunc(pilot *v1alpha1.Pilot) error {
	glog.V(4).Infof("ElasticsearchController: syncing current pilot %q", pilot.Name)
	if pilot.Status.Elasticsearch == nil {
		pilot.Status.Elasticsearch = &v1alpha1.ElasticsearchPilotStatus{}
	}
	// set the ES document count to nil to indicate an unknown number of
	// documents in case obtaining the document count fails. This prevents the
	// node being shut down if it is not safe to do so.
	pilot.Status.Elasticsearch.Documents = nil
	if p.localESClient == nil {
		return fmt.Errorf("local elasticsearch client not available")
	}
	// TODO: use context with a timeout
	statsList, err := p.localESClient.NodesStats().NodeId(elasticsearchLocalNodeID).Do(context.Background())
	if err != nil {
		return err
	}
	// we can iterate over the results as the elastic client should only return
	// a single node entry or none as we specify a single nodeID.
	for _, stats := range statsList.Nodes {
		docCount := stats.Indices.Docs.Count
		pilot.Status.Elasticsearch.Documents = &docCount
	}
	return nil
}

func (p *Pilot) leaderElectedSyncFunc(pilot *v1alpha1.Pilot) error {
	glog.V(4).Infof("ElasticsearchController: leader elected sync of pilot %q", pilot.Name)
	return nil
}
<commit_msg>Use pilotName as selector when getting document count<commit_after>package v5

import (
	"context"
	"fmt"

	"github.com/golang/glog"

	"github.com/jetstack/navigator/pkg/apis/navigator/v1alpha1"
)

const (
	elasticsearchLocalNodeID = "_local"
)

func (p *Pilot) syncFunc(pilot *v1alpha1.Pilot) error {
	glog.V(4).Infof("ElasticsearchController: syncing current pilot %q", pilot.Name)
	if pilot.Status.Elasticsearch == nil {
		pilot.Status.Elasticsearch = &v1alpha1.ElasticsearchPilotStatus{}
	}
	// set the ES document count to nil to indicate an unknown number of
	// documents in case obtaining the document count fails. This prevents the
	// node being shut down if it is not safe to do so.
	pilot.Status.Elasticsearch.Documents = nil
	if p.localESClient == nil {
		return fmt.Errorf("local elasticsearch client not available")
	}
	// TODO: use context with a timeout
	statsList, err := p.localESClient.NodesStats().NodeId(p.Options.GenericPilotOptions.PilotName).Do(context.Background())
	if err != nil {
		return err
	}
	// we can iterate over the results as the elastic client should only return
	// a single node entry or none as we specify a single nodeID.
	for _, stats := range statsList.Nodes {
		docCount := stats.Indices.Docs.Count
		pilot.Status.Elasticsearch.Documents = &docCount
	}
	return nil
}

func (p *Pilot) leaderElectedSyncFunc(pilot *v1alpha1.Pilot) error {
	glog.V(4).Infof("ElasticsearchController: leader elected sync of pilot %q", pilot.Name)
	return nil
}
<|endoftext|>


<commit_before>package main

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

func main() {
	err := filepath.Walk("./vendor", func(path string, _ os.FileInfo, _ error) error {
		base := filepath.Base(path)
		ext := filepath.Ext(base)
		if strings.TrimSuffix(base, ext) == "LICENSE" {
			switch strings.TrimPrefix(strings.ToLower(ext), ".") {
			case "", "code", "docs", "libyaml", "md", "txt":
				fmt.Println("Name:", path)
				lb, err := ioutil.ReadFile(path)
				if err != nil {
					log.Fatal(err)
				}
				fmt.Println("License:", string(lb))
			}
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>tools/licensegen: consider COPYING files<commit_after>package main

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

func main() {
	err := filepath.Walk("./vendor", func(path string, _ os.FileInfo, _ error) error {
		base := filepath.Base(path)
		ext := filepath.Ext(base)
		if stem := strings.TrimSuffix(base, ext); stem == "LICENSE" || stem == "COPYING" {
			switch strings.TrimPrefix(strings.ToLower(ext), ".") {
			case "", "code", "docs", "libyaml", "md", "txt":
				fmt.Println("Name:", path)
				lb, err := ioutil.ReadFile(path)
				if err != nil {
					log.Fatal(err)
				}
				fmt.Println("License:", string(lb))
			}
		}
		return nil
	})
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package q

import (
	"database/sql"
	"fmt"
	"testing"

	"github.com/oov/q/qutil"
)

var expressionTests = []struct {
	Name string
	E    Expression
	Want map[qutil.Dialect]string
	V    string
}{
	{
		Name: `=`,
		E:    Eq(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `=(NULL)`,
		// Unsafe is workaround for PostgreSQL "could not determine data type of parameter $1" error.
		E:    Eq(Unsafe(0), nil),
		Want: resultMap("0", "false", "0"),
		V:    `0 IS NULL []`,
	},
	{
		Name: `=(NULL)2`,
		E:    Eq(nil, Unsafe(0)),
		Want: resultMap("0", "false", "0"),
		V:    `0 IS NULL []`,
	},
	{
		Name: `=(NULL)3`,
		E:    Eq(nil, nil),
		Want: resultMap("1", "true", "1"),
		V:    `NULL IS NULL []`,
	},
	{
		Name: `= empty slice`,
		E:    Eq(0, []int{}),
		Want: resultMap("0", "false", "0"),
		V:    `'IN' = '()' []`,
	},
	{
		Name: `= slice`,
		E:    Eq(0, []int{1, 2, 3}),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `!=`,
		E:    Neq(0, 1),
		Want: resultMap("1", "true", "1"),
		V:    `? != ? [0 1]`,
	},
	{
		Name: `!=(NULL)`,
		E:    Neq(Unsafe(0), nil),
		Want: resultMap("1", "true", "1"),
		V:    `0 IS NOT NULL []`,
	},
	{
		Name: `!=(NULL)2`,
		E:    Neq(nil, Unsafe(0)),
		Want: resultMap("1", "true", "1"),
		V:    `0 IS NOT NULL []`,
	},
	{
		Name: `!=(NULL)3`,
		E:    Neq(nil, nil),
		Want: resultMap("0", "false", "0"),
		V:    `NULL IS NOT NULL []`,
	},
	{
		Name: `!= empty slice`,
		E:    Neq(0, []int{}),
		Want: resultMap("1", "true", "1"),
		V:    `'IN' != '()' []`,
	},
	{
		Name: `!= slice`,
		E:    Neq(0, []int{1, 2, 3}),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `>`,
		E:    Gt(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? > ? [0 1]`,
	},
	{
		Name: `>=`,
		E:    Gte(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? >= ? [0 1]`,
	},
	{
		Name: `<`,
		E:    Lt(1, 0),
		Want: resultMap("0", "false", "0"),
		V:    `? < ? [1 0]`,
	},
	{
		Name: `<=`,
		E:    Lte(1, 0),
		Want: resultMap("0", "false", "0"),
		V:    `? <= ? [1 0]`,
	},
	{
		Name: `IN empty slice`,
		E:    In(0, []int{}),
		Want: resultMap("0", "false", "0"),
		V:    `'IN' = '()' []`,
	},
	{
		Name: `IN slice`,
		E:    In(0, []int{1, 2, 3}),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `IN builder`,
		E:    In(0, Select().Column(C("id")).From(T("user"))),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (SELECT "id" FROM "user") [0]`,
	},
	{
		Name: `NOT IN empty slice`,
		E:    NotIn(0, []int{}),
		Want: resultMap("1", "true", "1"),
		V:    `'IN' != '()' []`,
	},
	{
		Name: `NOT IN slice`,
		E:    NotIn(0, []int{1, 2, 3}),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `NOT IN builder`,
		E:    NotIn(0, Select().Column(C("id")).From(T("user"))),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (SELECT "id" FROM "user") [0]`,
	},
	{
		Name: `AND empty`,
		E:    And(),
		Want: resultMap("0", "false", "0"),
		V:    `('empty' = 'AND') []`,
	},
	{
		Name: `AND 1`,
		E:    And(Eq(0, 1)),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `AND 2`,
		E:    And(Eq(0, 1), Neq(0, 0)),
		Want: resultMap("0", "false", "0"),
		V:    `(? = ?)AND(? != ?) [0 1 0 0]`,
	},
	{
		Name: `OR empty`,
		E:    Or(),
		Want: resultMap("0", "false", "0"),
		V:    `('empty' = 'OR') []`,
	},
	{
		Name: `OR 1`,
		E:    Or(Eq(0, 1)),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `OR 2`,
		E:    Or(Eq(0, 1), Neq(0, 0)),
		Want: resultMap("0", "false", "0"),
		V:    `(? = ?)OR(? != ?) [0 1 0 0]`,
	},
	{
		Name: `Unsafe`,
		E:    Unsafe(3, "%", 2),
		Want: resultMap("1", "1", "1"),
		V:    `3%2 []`,
	},
	{
		Name: `Unsafe + Expression nil`,
		E:    Unsafe(C("id"), " IS ", nil),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IS NULL []`,
	},
	{
		Name: `Unsafe + V`,
		E:    Unsafe(C("id"), " = ", V(0)),
		Want: resultMap("0", "false", "0"),
		V:    `"id" = ? [0]`,
	},
	{
		Name: `Unsafe + InV(not slice)`,
		E:    Unsafe(C("id"), " IN ", InV(0)),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IN (?) [0]`,
	},
	{
		Name: `Unsafe + InV(slice)`,
		E:    Unsafe(C("id"), " IN ", InV([]int{100, 101, 102})),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IN (?,?,?) [100 101 102]`,
	},
	{
		Name: `COUNT(*)`,
		E:    CountAll(),
		Want: resultMap("2", "2", "2"),
		V:    `COUNT(*) []`,
	},
	{
		Name: `COUNT`,
		E:    Count(C("id")),
		Want: resultMap("2", "2", "2"),
		V:    `COUNT("id") []`,
	},
	{
		Name: `AVG`,
		E:    Avg(C("age")),
		Want: resultMap("29.5000", "29.5000000000000000", "29.5"),
		V:    `AVG("age") []`,
	},
	{
		Name: `MAX`,
		E:    Max(C("age")),
		Want: resultMap("44", "44", "44"),
		V:    `MAX("age") []`,
	},
	{
		Name: `MIN`,
		E:    Min(C("age")),
		Want: resultMap("15", "15", "15"),
		V:    `MIN("age") []`,
	},
	{
		Name: `SUM`,
		E:    Sum(C("age")),
		Want: resultMap("59", "59", "59"),
		V:    `SUM("age") []`,
	},
	{
		Name: `CHAR_LENGTH`,
		E:    CharLength(C("name")),
		Want: resultMap("6", "6", "6"),
		V:    `CHAR_LENGTH("name") []`,
	},
}

func TestExpression(t *testing.T) {
	for i, test := range expressionTests {
		if r := fmt.Sprint(test.E); r != test.V {
			t.Errorf("test[%d] %s want %s got %s", i, test.Name, test.V, r)
		}
	}
}

func resultMap(r ...string) map[qutil.Dialect]string {
	return map[qutil.Dialect]string{
		MySQL:      r[0],
		PostgreSQL: r[1],
		SQLite:     r[2],
	}
}

func TestExpressionOnDB(t *testing.T) {
	for _, testData := range testModel {
		err := testData.tester(func(db *sql.DB, d qutil.Dialect) {
			defer exec(t, "drops", db, d, testData.drops)
			exec(t, "drops", db, d, testData.drops)
			exec(t, "creates", db, d, testData.creates)
			exec(t, "inserts", db, d, testData.inserts)
			for i, test := range expressionTests {
				func() {
					var r string
					sql, args := Select().Column(test.E.C()).From(T("user")).Limit(1).SetDialect(d).ToSQL()
					if err := db.QueryRow(sql, args...).Scan(&r); err != nil {
						t.Fatalf("%s tests[%d] %s Error: %v\n%s", d, i, test.Name, err, sql)
					}
					if fmt.Sprint(r) != fmt.Sprint(test.Want[d]) {
						t.Errorf("%s test[%d] %s want %v got %v", d, i, test.Name, test.Want[d], r)
					}
				}()
			}
		})
		if err != nil {
			t.Fatal(err)
		}
	}
}
<commit_msg>add tests<commit_after>package q

import (
	"database/sql"
	"fmt"
	"testing"

	"github.com/oov/q/qutil"
)

var expressionTests = []struct {
	Name string
	E    Expression
	Want map[qutil.Dialect]string
	V    string
}{
	{
		Name: `=`,
		E:    Eq(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `=(NULL)`,
		// Unsafe is workaround for PostgreSQL "could not determine data type of parameter $1" error.
		E:    Eq(Unsafe(0), nil),
		Want: resultMap("0", "false", "0"),
		V:    `0 IS NULL []`,
	},
	{
		Name: `=(NULL)2`,
		E:    Eq(nil, Unsafe(0)),
		Want: resultMap("0", "false", "0"),
		V:    `0 IS NULL []`,
	},
	{
		Name: `=(NULL)3`,
		E:    Eq(nil, nil),
		Want: resultMap("1", "true", "1"),
		V:    `NULL IS NULL []`,
	},
	{
		Name: `= empty slice`,
		E:    Eq(0, []int{}),
		Want: resultMap("0", "false", "0"),
		V:    `'IN' = '()' []`,
	},
	{
		Name: `= slice`,
		E:    Eq(0, []int{1, 2, 3}),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `!=`,
		E:    Neq(0, 1),
		Want: resultMap("1", "true", "1"),
		V:    `? != ? [0 1]`,
	},
	{
		Name: `!=(NULL)`,
		E:    Neq(Unsafe(0), nil),
		Want: resultMap("1", "true", "1"),
		V:    `0 IS NOT NULL []`,
	},
	{
		Name: `!=(NULL)2`,
		E:    Neq(nil, Unsafe(0)),
		Want: resultMap("1", "true", "1"),
		V:    `0 IS NOT NULL []`,
	},
	{
		Name: `!=(NULL)3`,
		E:    Neq(nil, nil),
		Want: resultMap("0", "false", "0"),
		V:    `NULL IS NOT NULL []`,
	},
	{
		Name: `!= empty slice`,
		E:    Neq(0, []int{}),
		Want: resultMap("1", "true", "1"),
		V:    `'IN' != '()' []`,
	},
	{
		Name: `!= slice`,
		E:    Neq(0, []int{1, 2, 3}),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `>`,
		E:    Gt(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? > ? [0 1]`,
	},
	{
		Name: `>=`,
		E:    Gte(0, 1),
		Want: resultMap("0", "false", "0"),
		V:    `? >= ? [0 1]`,
	},
	{
		Name: `<`,
		E:    Lt(1, 0),
		Want: resultMap("0", "false", "0"),
		V:    `? < ? [1 0]`,
	},
	{
		Name: `<=`,
		E:    Lte(1, 0),
		Want: resultMap("0", "false", "0"),
		V:    `? <= ? [1 0]`,
	},
	{
		Name: `IN empty slice`,
		E:    In(0, []int{}),
		Want: resultMap("0", "false", "0"),
		V:    `'IN' = '()' []`,
	},
	{
		Name: `IN slice`,
		E:    In(0, []int{1, 2, 3}),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `IN builder`,
		E:    In(0, Select().Column(C("id")).From(T("user"))),
		Want: resultMap("0", "false", "0"),
		V:    `? IN (SELECT "id" FROM "user") [0]`,
	},
	{
		Name: `NOT IN empty slice`,
		E:    NotIn(0, []int{}),
		Want: resultMap("1", "true", "1"),
		V:    `'IN' != '()' []`,
	},
	{
		Name: `NOT IN slice`,
		E:    NotIn(0, []int{1, 2, 3}),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (?,?,?) [0 1 2 3]`,
	},
	{
		Name: `NOT IN builder`,
		E:    NotIn(0, Select().Column(C("id")).From(T("user"))),
		Want: resultMap("1", "true", "1"),
		V:    `? NOT IN (SELECT "id" FROM "user") [0]`,
	},
	{
		Name: `AND empty`,
		E:    And(),
		Want: resultMap("0", "false", "0"),
		V:    `('empty' = 'AND') []`,
	},
	{
		Name: `AND 1`,
		E:    And(Eq(0, 1)),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `AND 2`,
		E:    And(Eq(0, 1), Neq(0, 0)),
		Want: resultMap("0", "false", "0"),
		V:    `(? = ?)AND(? != ?) [0 1 0 0]`,
	},
	{
		Name: `OR empty`,
		E:    Or(),
		Want: resultMap("0", "false", "0"),
		V:    `('empty' = 'OR') []`,
	},
	{
		Name: `OR 1`,
		E:    Or(Eq(0, 1)),
		Want: resultMap("0", "false", "0"),
		V:    `? = ? [0 1]`,
	},
	{
		Name: `OR 2`,
		E:    Or(Eq(0, 1), Neq(0, 0)),
		Want: resultMap("0", "false", "0"),
		V:    `(? = ?)OR(? != ?) [0 1 0 0]`,
	},
	{
		Name: `Unsafe`,
		E:    Unsafe(3, "%", 2),
		Want: resultMap("1", "1", "1"),
		V:    `3%2 []`,
	},
	{
		Name: `Unsafe + Expression nil`,
		E:    Unsafe(C("id"), " IS ", nil),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IS NULL []`,
	},
	{
		Name: `Unsafe + V`,
		E:    Unsafe(C("id"), " = ", V(0)),
		Want: resultMap("0", "false", "0"),
		V:    `"id" = ? [0]`,
	},
	{
		Name: `Unsafe + InV(not slice)`,
		E:    Unsafe(C("id"), " IN ", InV(0)),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IN (?) [0]`,
	},
	{
		Name: `Unsafe + InV(slice)`,
		E:    Unsafe(C("id"), " IN ", InV([]int{100, 101, 102})),
		Want: resultMap("0", "false", "0"),
		V:    `"id" IN (?,?,?) [100 101 102]`,
	},
	{
		Name: `COUNT(*)`,
		E:    CountAll(),
		Want: resultMap("2", "2", "2"),
		V:    `COUNT(*) []`,
	},
	{
		Name: `COUNT`,
		E:    Count(C("id")),
		Want: resultMap("2", "2", "2"),
		V:    `COUNT("id") []`,
	},
	{
		Name: `AVG`,
		E:    Avg(C("age")),
		Want: resultMap("29.5000", "29.5000000000000000", "29.5"),
		V:    `AVG("age") []`,
	},
	{
		Name: `MAX`,
		E:    Max(C("age")),
		Want: resultMap("44", "44", "44"),
		V:    `MAX("age") []`,
	},
	{
		Name: `MIN`,
		E:    Min(C("age")),
		Want: resultMap("15", "15", "15"),
		V:    `MIN("age") []`,
	},
	{
		Name: `SUM`,
		E:    Sum(C("age")),
		Want: resultMap("59", "59", "59"),
		V:    `SUM("age") []`,
	},
	{
		Name: `CHAR_LENGTH`,
		E:    CharLength(C("name")),
		Want: resultMap("6", "6", "6"),
		V:    `CHAR_LENGTH("name") []`,
	},
}

func TestNullCUnimplementedPanic(t *testing.T) {
	defer func() {
		if e := recover(); e == nil {
			t.Error("want Panic got Nothing")
		}
	}()
	nullExpr{}.C()
}

func TestInVEmptySlicePanic(t *testing.T) {
	defer func() {
		if e := recover(); e == nil {
			t.Error("want Panic got Nothing")
		}
	}()
	InV([]int{})
}

func TestExpression(t *testing.T) {
	for i, test := range expressionTests {
		if r := fmt.Sprint(test.E); r != test.V {
			t.Errorf("test[%d] %s want %s got %s", i, test.Name, test.V, r)
		}
	}
}

func resultMap(r ...string) map[qutil.Dialect]string {
	return map[qutil.Dialect]string{
		MySQL:      r[0],
		PostgreSQL: r[1],
		SQLite:     r[2],
	}
}

func TestExpressionOnDB(t *testing.T) {
	for _, testData := range testModel {
		err := testData.tester(func(db *sql.DB, d qutil.Dialect) {
			defer exec(t, "drops", db, d, testData.drops)
			exec(t, "drops", db, d, testData.drops)
			exec(t, "creates", db, d, testData.creates)
			exec(t, "inserts", db, d, testData.inserts)
			for i, test := range expressionTests {
				func() {
					var r string
					sql, args := Select().Column(test.E.C()).From(T("user")).Limit(1).SetDialect(d).ToSQL()
					if err := db.QueryRow(sql, args...).Scan(&r); err != nil {
						t.Fatalf("%s tests[%d] %s Error: %v\n%s", d, i, test.Name, err, sql)
					}
					if fmt.Sprint(r) != fmt.Sprint(test.Want[d]) {
						t.Errorf("%s test[%d] %s want %v got %v", d, i, test.Name, test.Want[d], r)
					}
				}()
			}
		})
		if err != nil {
			t.Fatal(err)
		}
	}
}

func TestVariableStringer(t *testing.T) {
	if want, r := `? [1]`, fmt.Sprint(V(1)); r != want {
		t.Errorf(`V(1) want %s got %s`, want, r)
	}
	if want, r := `? AS "v" [1]`, fmt.Sprint(V(1).C("v")); r != want {
		t.Errorf(`V(1).C() want %s got %s`, want, r)
	}
	if want, r := `(?,?,?) [1 2 3]`, fmt.Sprint(InV([]int{1, 2, 3})); r != want {
		t.Errorf(`InV([]int{1, 2, 3}) want %s got %s`, want, r)
	}
	if want, r := `(?) AS "v" [1]`, fmt.Sprint(InV([]int{1}).C("v")); r != want {
		t.Errorf(`InV([]int{1}).C() want %s got %s`, want, r)
	}
}
<|endoftext|>


<commit_before>// +build linux

/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 netns

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"gopkg.in/fsnotify/fsnotify.v1"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
	"github.com/skydive-project/skydive/topology/probes/netlink"
	"github.com/vishvananda/netns"
)

// NetNSProbe describes a netlink probe in a network namespace
type NetNSProbe struct {
	common.RWMutex
	Graph              *graph.Graph
	Root               *graph.Node
	NetLinkProbe       *netlink.NetLinkProbe
	pathToNetNS        map[string]*NetNs
	netNsNetLinkProbes map[string]*netNsNetLinkProbe
	rootNs             *NetNs
	watcher            *fsnotify.Watcher
	pending            chan string
	exclude            []string
}

// NetNs describes a network namespace path associated with a device / inode
type NetNs struct {
	path string
	dev  uint64
	ino  uint64
}

// extends the original struct to add use count number
type netNsNetLinkProbe struct {
	*netlink.NetNsNetLinkProbe
	useCount int
}

func getNetNSName(path string) string {
	s := strings.Split(path, "/")
	return s[len(s)-1]
}

func (ns *NetNs) String() string {
	return fmt.Sprintf("%d,%d", ns.dev, ns.ino)
}

// Equal compares two NetNs objects
func (ns *NetNs) Equal(o *NetNs) bool {
	return (ns.dev == o.dev && ns.ino == o.ino)
}

func (u *NetNSProbe) checkNamespace(path string) error {
	// When a new network namespace has been seen by inotify, the path to
	// the namespace may still be a regular file, not a bind mount to the
	// file in /proc/<pid>/tasks/<tid>/ns/net yet, so we wait a bit for the
	// bind mount to be set up

	return common.Retry(func() error {
		var stats, parentStats syscall.Stat_t
		fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}

		err = syscall.Fstat(fd, &stats)
		syscall.Close(fd)
		if err != nil {
			return err
		}

		if parent := filepath.Dir(path); parent != "" {
			if err := syscall.Stat(parent, &parentStats); err == nil {
				if stats.Dev == parentStats.Dev {
					return fmt.Errorf("%s does not seem to be a valid namespace", path)
				}
			}
		}

		return nil
	}, 30, time.Millisecond*100)
}

// Register a new network namespace path
func (u *NetNSProbe) Register(path string, name string) (*graph.Node, error) {
	logging.GetLogger().Debugf("Register network namespace: %s", path)

	if err := u.checkNamespace(path); err != nil {
		return nil, err
	}

	var stats syscall.Stat_t
	if err := syscall.Stat(path, &stats); err != nil {
		return nil, fmt.Errorf("Failed to stat namespace %s: %s", path, err)
	}

	newns := &NetNs{path: path, dev: stats.Dev, ino: stats.Ino}

	// avoid hard link to root ns
	if u.rootNs.Equal(newns) {
		return u.Root, nil
	}

	u.Lock()
	defer u.Unlock()

	_, ok := u.pathToNetNS[path]
	if !ok {
		u.pathToNetNS[path] = newns
	}

	nsString := newns.String()
	if probe, ok := u.netNsNetLinkProbes[nsString]; ok {
		probe.useCount++
		logging.GetLogger().Debugf("Increasing counter for namespace %s to %d", nsString, probe.useCount)
		return probe.Root, nil
	}

	u.Graph.Lock()

	logging.GetLogger().Debugf("Network namespace added: %s", nsString)
	metadata := graph.Metadata{
		"Name":   name,
		"Type":   "netns",
		"Path":   path,
		"Inode":  int64(newns.ino),
		"Device": int64(newns.dev),
	}

	n := u.Graph.NewNode(graph.GenID(), metadata)
	topology.AddOwnershipLink(u.Graph, u.Root, n, nil)

	u.Graph.Unlock()

	logging.GetLogger().Debugf("Registering namespace: %s", nsString)
	probe, err := u.NetLinkProbe.Register(path, n)
	if err != nil {
		return nil, fmt.Errorf("Could not register netlink probe within namespace: %s", err)
	}

	u.netNsNetLinkProbes[nsString] = &netNsNetLinkProbe{NetNsNetLinkProbe: probe, useCount: 1}

	return n, nil
}

// Unregister a network namespace path
func (u *NetNSProbe) Unregister(path string) {
	logging.GetLogger().Debugf("Unregister network Namespace: %s", path)

	u.Lock()
	defer u.Unlock()

	ns, ok := u.pathToNetNS[path]
	if !ok {
		return
	}

	delete(u.pathToNetNS, path)
	nsString := ns.String()
	probe, ok := u.netNsNetLinkProbes[nsString]
	if !ok {
		logging.GetLogger().Debugf("No existing network namespace found: %s (%s)", nsString)
		return
	}

	if probe.useCount > 1 {
		probe.useCount--
		logging.GetLogger().Debugf("Decremented counter for namespace %s to %d", nsString, probe.useCount)
		return
	}

	u.NetLinkProbe.Unregister(path)
	logging.GetLogger().Debugf("Network namespace deleted: %s", nsString)

	u.Graph.Lock()
	defer u.Graph.Unlock()

	for _, child := range u.Graph.LookupChildren(probe.Root, nil, nil) {
		u.Graph.DelNode(child)
	}
	u.Graph.DelNode(probe.Root)

	delete(u.netNsNetLinkProbes, nsString)
}

func (u *NetNSProbe) initializeRunPath(path string) {
	for {
		if _, err := os.Stat(path); err == nil {
			break
		}
		time.Sleep(time.Second)
	}

	if err := u.watcher.Add(path); err != nil {
		logging.GetLogger().Errorf("Unable to Watch %s: %s", path, err)
	}

	files, _ := ioutil.ReadDir(path)
LOOP:
	for _, f := range files {
		fullpath, name := path+"/"+f.Name(), f.Name()

		if u.isPathExcluded(fullpath) {
			continue LOOP
		}

		if _, err := u.Register(fullpath, name); err != nil {
			logging.GetLogger().Errorf("Failed to register namespace %s: %s", fullpath, err)
			continue
		}
	}
	logging.GetLogger().Debugf("NetNSProbe initialized %s", path)
}

func (u *NetNSProbe) start() {
	logging.GetLogger().Debugf("NetNSProbe initialized")
LOOP:
	for {
		select {
		case path := <-u.pending:
			go u.initializeRunPath(path)
		case ev := <-u.watcher.Events:
			if u.isPathExcluded(ev.Name) {
				continue LOOP
			}
			if ev.Op&fsnotify.Create == fsnotify.Create {
				if _, err := u.Register(ev.Name, getNetNSName(ev.Name)); err != nil {
					logging.GetLogger().Errorf("Failed to register namespace %s: %s", ev.Name, err)
					continue
				}
			}
			if ev.Op&fsnotify.Remove == fsnotify.Remove {
				u.Unregister(ev.Name)
			}

		case err := <-u.watcher.Errors:
			logging.GetLogger().Errorf("Error while watching network namespace: %s", err)
		}
	}
}

// Watch add a path to the inotify watcher
func (u *NetNSProbe) Watch(path string) {
	u.pending <- path
}

// Start the probe
func (u *NetNSProbe) Start() {
	go u.start()
}

// Stop the probe
func (u *NetNSProbe) Stop() {
	u.NetLinkProbe.Stop()
}

func (u *NetNSProbe) isPathExcluded(path string) bool {
	u.RLock()
	defer u.RUnlock()

	for _, e := range u.exclude {
		if e == path {
			return true
		}
	}
	return false
}

// Exclude specify path to not process
func (u *NetNSProbe) Exclude(paths ...string) {
	u.Lock()
	u.exclude = append(u.exclude, paths...)
	u.Unlock()
}

// NewNetNSProbe creates a new network namespace probe
func NewNetNSProbe(g *graph.Graph, n *graph.Node, nlProbe *netlink.NetLinkProbe) (*NetNSProbe, error) {
	if uid := os.Geteuid(); uid != 0 {
		return nil, errors.New("NetNS probe has to be run as root")
	}

	ns, err := netns.Get()
	if err != nil {
		return nil, errors.New("Failed to get root namespace")
	}
	defer ns.Close()

	var stats syscall.Stat_t
	if err = syscall.Fstat(int(ns), &stats); err != nil {
		return nil, errors.New("Failed to stat root namespace")
	}
	rootNs := &NetNs{dev: stats.Dev, ino: stats.Ino}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("Unable to create a new Watcher: %s", err)
	}

	nsProbe := &NetNSProbe{
		Graph:              g,
		Root:               n,
		NetLinkProbe:       nlProbe,
		pathToNetNS:        make(map[string]*NetNs),
		netNsNetLinkProbes: make(map[string]*netNsNetLinkProbe),
		rootNs:             rootNs,
		watcher:            watcher,
		pending:            make(chan string, 10),
	}

	if path := config.GetString("netns.run_path"); path != "" {
		nsProbe.Watch(path)
	}

	return nsProbe, nil
}
<commit_msg>netns : don't check parent if path is a symlink<commit_after>// +build linux

/*
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 netns

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"

	"gopkg.in/fsnotify/fsnotify.v1"

	"github.com/skydive-project/skydive/common"
	"github.com/skydive-project/skydive/config"
	"github.com/skydive-project/skydive/logging"
	"github.com/skydive-project/skydive/topology"
	"github.com/skydive-project/skydive/topology/graph"
	"github.com/skydive-project/skydive/topology/probes/netlink"
	"github.com/vishvananda/netns"
)

// NetNSProbe describes a netlink probe in a network namespace
type NetNSProbe struct {
	common.RWMutex
	Graph              *graph.Graph
	Root               *graph.Node
	NetLinkProbe       *netlink.NetLinkProbe
	pathToNetNS        map[string]*NetNs
	netNsNetLinkProbes map[string]*netNsNetLinkProbe
	rootNs             *NetNs
	watcher            *fsnotify.Watcher
	pending            chan string
	exclude            []string
}

// NetNs describes a network namespace path associated with a device / inode
type NetNs struct {
	path string
	dev  uint64
	ino  uint64
}

// extends the original struct to add use count number
type netNsNetLinkProbe struct {
	*netlink.NetNsNetLinkProbe
	useCount int
}

func getNetNSName(path string) string {
	s := strings.Split(path, "/")
	return s[len(s)-1]
}

func (ns *NetNs) String() string {
	return fmt.Sprintf("%d,%d", ns.dev, ns.ino)
}

// Equal compares two NetNs objects
func (ns *NetNs) Equal(o *NetNs) bool {
	return (ns.dev == o.dev && ns.ino == o.ino)
}

func (u *NetNSProbe) checkNamespace(path string) error {
	// When a new network namespace has been seen by inotify, the path to
	// the namespace may still be a regular file, not a bind mount to the
	// file in /proc/<pid>/tasks/<tid>/ns/net yet, so we wait a bit for the
	// bind mount to be set up

	return common.Retry(func() error {
		var stats, parentStats syscall.Stat_t
		fd, err := syscall.Open(path, syscall.O_RDONLY, 0)
		if err != nil {
			return err
		}

		err = syscall.Fstat(fd, &stats)
		syscall.Close(fd)
		if err != nil {
			return err
		}

		if (stats.Mode & syscall.S_IFLNK) > 0 {
			return nil
		}

		if parent := filepath.Dir(path); parent != "" {
			if err := syscall.Stat(parent, &parentStats); err == nil {
				if stats.Dev == parentStats.Dev {
					return fmt.Errorf("%s does not seem to be a valid namespace", path)
				}
			}
		}

		return nil
	}, 30, time.Millisecond*100)
}

// Register a new network namespace path
func (u *NetNSProbe) Register(path string, name string) (*graph.Node, error) {
	logging.GetLogger().Debugf("Register network namespace: %s", path)

	if err := u.checkNamespace(path); err != nil {
		return nil, err
	}

	var stats syscall.Stat_t
	if err := syscall.Stat(path, &stats); err != nil {
		return nil, fmt.Errorf("Failed to stat namespace %s: %s", path, err)
	}

	newns := &NetNs{path: path, dev: stats.Dev, ino: stats.Ino}

	// avoid hard link to root ns
	if u.rootNs.Equal(newns) {
		return u.Root, nil
	}

	u.Lock()
	defer u.Unlock()

	_, ok := u.pathToNetNS[path]
	if !ok {
		u.pathToNetNS[path] = newns
	}

	nsString := newns.String()
	if probe, ok := u.netNsNetLinkProbes[nsString]; ok {
		probe.useCount++
		logging.GetLogger().Debugf("Increasing counter for namespace %s to %d", nsString, probe.useCount)
		return probe.Root, nil
	}

	u.Graph.Lock()

	logging.GetLogger().Debugf("Network namespace added: %s", nsString)
	metadata := graph.Metadata{
		"Name":   name,
		"Type":   "netns",
		"Path":   path,
		"Inode":  int64(newns.ino),
		"Device": int64(newns.dev),
	}

	n := u.Graph.NewNode(graph.GenID(), metadata)
	topology.AddOwnershipLink(u.Graph, u.Root, n, nil)

	u.Graph.Unlock()

	logging.GetLogger().Debugf("Registering namespace: %s", nsString)

	var probe *netlink.NetNsNetLinkProbe
	err := common.Retry(func() error {
		var err error
		probe, err = u.NetLinkProbe.Register(path, n)
		if err != nil {
			return fmt.Errorf("Could not register netlink probe within namespace: %s", err)
		}
		return nil
	}, 100, 10*time.Millisecond)
	if err != nil {
		return nil, err
	}

	u.netNsNetLinkProbes[nsString] = &netNsNetLinkProbe{NetNsNetLinkProbe: probe, useCount: 1}

	return n, nil
}

// Unregister a network namespace path
func (u *NetNSProbe) Unregister(path string) {
	logging.GetLogger().Debugf("Unregister network Namespace: %s", path)

	u.Lock()
	defer u.Unlock()

	ns, ok := u.pathToNetNS[path]
	if !ok {
		return
	}

	delete(u.pathToNetNS, path)
	nsString := ns.String()
	probe, ok := u.netNsNetLinkProbes[nsString]
	if !ok {
		logging.GetLogger().Debugf("No existing network namespace found: %s (%s)", nsString)
		return
	}

	if probe.useCount > 1 {
		probe.useCount--
		logging.GetLogger().Debugf("Decremented counter for namespace %s to %d", nsString, probe.useCount)
		return
	}

	u.NetLinkProbe.Unregister(path)
	logging.GetLogger().Debugf("Network namespace deleted: %s", nsString)

	u.Graph.Lock()
	defer u.Graph.Unlock()

	for _, child := range u.Graph.LookupChildren(probe.Root, nil, nil) {
		u.Graph.DelNode(child)
	}
	u.Graph.DelNode(probe.Root)

	delete(u.netNsNetLinkProbes, nsString)
}

func (u *NetNSProbe) initializeRunPath(path string) {
	for {
		if _, err := os.Stat(path); err == nil {
			break
		}
		time.Sleep(time.Second)
	}

	if err := u.watcher.Add(path); err != nil {
		logging.GetLogger().Errorf("Unable to Watch %s: %s", path, err)
	}

	files, _ := ioutil.ReadDir(path)
LOOP:
	for _, f := range files {
		fullpath, name := path+"/"+f.Name(), f.Name()

		if u.isPathExcluded(fullpath) {
			continue LOOP
		}

		if _, err := u.Register(fullpath, name); err != nil {
			logging.GetLogger().Errorf("Failed to register namespace %s: %s", fullpath, err)
			continue
		}
	}
	logging.GetLogger().Debugf("NetNSProbe initialized %s", path)
}

func (u *NetNSProbe) start() {
	logging.GetLogger().Debugf("NetNSProbe initialized")
LOOP:
	for {
		select {
		case path := <-u.pending:
			go u.initializeRunPath(path)
		case ev := <-u.watcher.Events:
			if u.isPathExcluded(ev.Name) {
				continue LOOP
			}
			if ev.Op&fsnotify.Create == fsnotify.Create {
				if _, err := u.Register(ev.Name, getNetNSName(ev.Name)); err != nil {
					logging.GetLogger().Errorf("Failed to register namespace %s: %s", ev.Name, err)
					continue
				}
			}
			if ev.Op&fsnotify.Remove == fsnotify.Remove {
				u.Unregister(ev.Name)
			}

		case err := <-u.watcher.Errors:
			logging.GetLogger().Errorf("Error while watching network namespace: %s", err)
		}
	}
}

// Watch add a path to the inotify watcher
func (u *NetNSProbe) Watch(path string) {
	u.pending <- path
}

// Start the probe
func (u *NetNSProbe) Start() {
	go u.start()
}

// Stop the probe
func (u *NetNSProbe) Stop() {
	u.NetLinkProbe.Stop()
}

func (u *NetNSProbe) isPathExcluded(path string) bool {
	u.RLock()
	defer u.RUnlock()

	for _, e := range u.exclude {
		if e == path {
			return true
		}
	}
	return false
}

// Exclude specify path to not process
func (u *NetNSProbe) Exclude(paths ...string) {
	u.Lock()
	u.exclude = append(u.exclude, paths...)
	u.Unlock()
}

// NewNetNSProbe creates a new network namespace probe
func NewNetNSProbe(g *graph.Graph, n *graph.Node, nlProbe *netlink.NetLinkProbe) (*NetNSProbe, error) {
	if uid := os.Geteuid(); uid != 0 {
		return nil, errors.New("NetNS probe has to be run as root")
	}

	ns, err := netns.Get()
	if err != nil {
		return nil, errors.New("Failed to get root namespace")
	}
	defer ns.Close()

	var stats syscall.Stat_t
	if err = syscall.Fstat(int(ns), &stats); err != nil {
		return nil, errors.New("Failed to stat root namespace")
	}
	rootNs := &NetNs{dev: stats.Dev, ino: stats.Ino}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("Unable to create a new Watcher: %s", err)
	}

	nsProbe := &NetNSProbe{
		Graph:              g,
		Root:               n,
		NetLinkProbe:       nlProbe,
		pathToNetNS:        make(map[string]*NetNs),
		netNsNetLinkProbes: make(map[string]*netNsNetLinkProbe),
		rootNs:             rootNs,
		watcher:            watcher,
		pending:            make(chan string, 10),
	}

	if path := config.GetString("netns.run_path"); path != "" {
		nsProbe.Watch(path)
	}

	return nsProbe, nil
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// +build go1.7

// [START trace_quickstart]

// Sample trace_quickstart creates traces incoming and outgoing requests.
package main

import (
	"log"
	"net/http"

	// Imports the Google Cloud Trace client package.
	"cloud.google.com/go/trace"
	"golang.org/x/net/context"
)

func main() {
	ctx := context.Background()

	// Sets your Google Cloud Platform project ID.
	projectID := "YOUR_PROJECT_ID"

	// Creates a client.
	traceClient, err := trace.NewClient(ctx, projectID)
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
	}

	httpClient := &http.Client{
		Transport: &trace.Transport{},
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		req, _ := http.NewRequest("GET", "https://metadata/users", nil)

		// The trace ID from the incoming request will be
		// propagated to the outgoing request.
		req = req.WithContext(r.Context())

		// The outgoing request will be traced with r's trace ID.
		if _, err := httpClient.Do(req); err != nil {
			log.Fatal(err)
		}
	})
	http.Handle("/foo", traceClient.HTTPHandler(handler))
	log.Fatal(http.ListenAndServe(":6060", nil))
}

// [END trace_quickstart]
<commit_msg>trace: replace the obsolete client with OpenCensus (#424)<commit_after>// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

// +build go1.8

// [START trace_quickstart]

// Sample trace_quickstart creates traces incoming and outgoing requests.
package main

import (
	"log"
	"net/http"

	"go.opencensus.io/exporter/stackdriver"
	"go.opencensus.io/exporter/stackdriver/propagation"
	"go.opencensus.io/plugin/ochttp"
	"go.opencensus.io/trace"
)

func main() {
	// Create an register a OpenCensus
	// Stackdriver Trace exporter.
	exporter, err := stackdriver.NewExporter(stackdriver.Options{
		ProjectID: "YOUR_PROJECT_ID",
	})
	if err != nil {
		log.Fatal(err)
	}
	trace.RegisterExporter(exporter)

	client := &http.Client{
		Transport: &ochttp.Transport{
			// Use Google Cloud propagation format.
			Propagation: &propagation.HTTPFormat{},
		},
	}

	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		req, _ := http.NewRequest("GET", "https://metadata/users", nil)

		// The trace ID from the incoming request will be
		// propagated to the outgoing request.
		req = req.WithContext(r.Context())

		// The outgoing request will be traced with r's trace ID.
		if _, err := client.Do(req); err != nil {
			log.Fatal(err)
		}
	})
	http.Handle("/foo", handler)
	log.Fatal(http.ListenAndServe(":6060", &ochttp.Handler{}))
}

// [END trace_quickstart]
<|endoftext|>


<commit_before>// Copyright 2017 The go-hep 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 server encapsulates the creation of the web server for root-srv.
package server

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"html/template"
	"image/color"
	"io"
	"log"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/satori/go.uuid"
	"go-hep.org/x/hep/hbook/rootcnv"
	"go-hep.org/x/hep/hbook/yodacnv"
	"go-hep.org/x/hep/hplot"
	"go-hep.org/x/hep/rootio"
)

const cookieName = "ROOTIO_SRV"

type server struct {
	mu       sync.RWMutex
	cookies  map[string]*http.Cookie
	sessions map[string]*dbFiles
}

// Init initializes the web server handles.
func Init() {
	app := newServer()
	http.Handle("/", app.wrap(app.rootHandle))
	http.Handle("/root-file-upload", app.wrap(app.uploadHandle))
	http.Handle("/plot-1d/", app.wrap(app.plotH1Handle))
	http.Handle("/plot-2d/", app.wrap(app.plotH2Handle))
	http.Handle("/plot-branch/", app.wrap(app.plotBranchHandle))
}

func newServer() *server {
	srv := &server{
		cookies:  make(map[string]*http.Cookie),
		sessions: make(map[string]*dbFiles),
	}
	go srv.run()
	return srv
}

func (srv *server) run() {
	ticker := time.NewTicker(5 * time.Minute)
	defer ticker.Stop()
	for range ticker.C {
		srv.gc()
	}
}

func (srv *server) gc() {
	srv.mu.Lock()
	defer srv.mu.Unlock()
	for name, cookie := range srv.cookies {
		now := time.Now()
		if now.After(cookie.Expires) {
			srv.sessions[name].close()
			delete(srv.sessions, name)
			delete(srv.cookies, name)
			cookie.MaxAge = -1
		}
	}
}

func (srv *server) expired(cookie *http.Cookie) bool {
	now := time.Now()
	return now.After(cookie.Expires)
}

func (srv *server) wrap(fn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := srv.setCookie(w, r)
		if err != nil {
			log.Printf("error retrieving cookie: %v\n", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		if err := fn(w, r); err != nil {
			log.Printf("error %q: %v\n", r.URL.Path, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

func (srv *server) setCookie(w http.ResponseWriter, r *http.Request) error {
	srv.mu.Lock()
	defer srv.mu.Unlock()
	cookie, err := r.Cookie(cookieName)
	if err != nil && err != http.ErrNoCookie {
		return err
	}

	if cookie != nil {
		if v, ok := srv.sessions[cookie.Value]; v == nil || !ok {
			srv.sessions[cookie.Value] = newDbFiles()
			srv.cookies[cookie.Value] = cookie
		}
		return nil
	}

	cookie = &http.Cookie{
		Name:    cookieName,
		Value:   uuid.NewV4().String(),
		Expires: time.Now().Add(24 * time.Hour),
	}
	srv.sessions[cookie.Value] = newDbFiles()
	srv.cookies[cookie.Value] = cookie
	http.SetCookie(w, cookie)
	return nil
}

func (srv *server) cookie(r *http.Request) (*http.Cookie, error) {
	srv.mu.RLock()
	defer srv.mu.RUnlock()
	cookie, err := r.Cookie(cookieName)
	if err != nil {
		return nil, err
	}

	if cookie == nil {
		return nil, http.ErrNoCookie
	}
	return srv.cookies[cookie.Value], nil
}

func (srv *server) db(r *http.Request) (*dbFiles, error) {
	srv.mu.RLock()
	defer srv.mu.RUnlock()
	cookie, err := srv.cookie(r)
	if err != nil {
		return nil, err
	}
	return srv.sessions[cookie.Value], nil
}

func (srv *server) rootHandle(w http.ResponseWriter, r *http.Request) error {
	switch r.Method {
	case http.MethodGet:
		// ok
	default:
		return fmt.Errorf("invalid request %q for /", r.Method)
	}

	crutime := time.Now().Unix()
	h := md5.New()
	io.WriteString(h, strconv.FormatInt(crutime, 10))
	token := fmt.Sprintf("%x", h.Sum(nil))

	t, err := template.New("upload").Parse(page)
	if err != nil {
		return err
	}

	return t.Execute(w, struct{ Token string }{token})
}

func (srv *server) uploadHandle(w http.ResponseWriter, r *http.Request) error {
	if r.Method != http.MethodPost {
		log.Printf("invalid request %q", r.Method)
		return fmt.Errorf("invalid request %q for /root-file-upload", r.Method)
	}

	r.ParseMultipartForm(500 << 20)
	f, handler, err := r.FormFile("upload-file")
	if err != nil {
		return err
	}
	_, err = f.Seek(0, 0)
	if err != nil {
		return err
	}

	rfile, err := rootio.NewReader(f, handler.Filename)
	if err != nil {
		return err
	}

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.set(handler.Filename, rfile)

	var nodes []jsNode

	db.RLock()
	defer db.RUnlock()
	for k, rfile := range db.files {
		node, err := fileJsTree(rfile, k)
		if err != nil {
			return err
		}
		nodes = append(nodes, node...)
	}
	sort.Sort(jsNodes(nodes))
	return json.NewEncoder(w).Encode(nodes)
}

func (srv *server) plotH1Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)
	url := r.URL.Path[len("/plot-1d/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}

	f := db.get(fname)
	obj, ok := f.Get(toks[1]) // FIXME(sbinet): handle sub-dirs
	if !ok {
		return fmt.Errorf("could not find %q in file %q", toks[1], fname)
	}

	robj, ok := obj.(yodacnv.Marshaler)
	if !ok {
		return fmt.Errorf("object %q could not be converted to hbook.H1D", toks[1])
	}
	h1d, err := rootcnv.H1D(robj)
	if err != nil {
		return err
	}

	plot, err := hplot.New()
	if err != nil {
		return err
	}
	plot.Title.Text = obj.(rootio.Named).Title()

	h, err := hplot.NewH1D(h1d)
	if err != nil {
		return err
	}
	h.Infos.Style = hplot.HInfoSummary
	h.Color = color.RGBA{255, 0, 0, 255}

	plot.Add(h, hplot.NewGrid())

	svg, err := renderSVG(plot)
	if err != nil {
		return err
	}

	return json.NewEncoder(w).Encode(string(svg))
}

func (srv *server) plotH2Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)

	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

func (srv *server) plotBranchHandle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)

	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

const page = `

    <title>go-hep/rootio file inspector</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
	<link rel="stylesheet" href="https://www.w3schools.com/w3css/3/w3.css">

	<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css" />

go-hep/rootio ROOT file inspector

	<form id="rootio-form" enctype="multipart/form-data" action="/root-file-upload" method="post">

		 Upload

		<input id="rootio-file" type="file" name="upload-file"/>
		<input type="hidden" name="token" value="{{.Token}}"/>
		<input type="hidden" value="upload" />
	</form>

`
<commit_msg>rootio/cmd/root-srv/server: refactor file-tree display<commit_after>// Copyright 2017 The go-hep 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 server encapsulates the creation of the web server for root-srv.
package server

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"html/template"
	"image/color"
	"io"
	"log"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/satori/go.uuid"
	"go-hep.org/x/hep/hbook/rootcnv"
	"go-hep.org/x/hep/hbook/yodacnv"
	"go-hep.org/x/hep/hplot"
	"go-hep.org/x/hep/rootio"
)

const cookieName = "ROOTIO_SRV"

type server struct {
	mu       sync.RWMutex
	cookies  map[string]*http.Cookie
	sessions map[string]*dbFiles
}

// Init initializes the web server handles.
func Init() {
	app := newServer()
	http.Handle("/", app.wrap(app.rootHandle))
	http.Handle("/root-file-upload", app.wrap(app.uploadHandle))
	http.Handle("/plot-1d/", app.wrap(app.plotH1Handle))
	http.Handle("/plot-2d/", app.wrap(app.plotH2Handle))
	http.Handle("/plot-branch/", app.wrap(app.plotBranchHandle))
}

func newServer() *server {
	srv := &server{
		cookies:  make(map[string]*http.Cookie),
		sessions: make(map[string]*dbFiles),
	}
	go srv.run()
	return srv
}

func (srv *server) run() {
	ticker := time.NewTicker(5 * time.Minute)
	defer ticker.Stop()
	for range ticker.C {
		srv.gc()
	}
}

func (srv *server) gc() {
	srv.mu.Lock()
	defer srv.mu.Unlock()
	for name, cookie := range srv.cookies {
		now := time.Now()
		if now.After(cookie.Expires) {
			srv.sessions[name].close()
			delete(srv.sessions, name)
			delete(srv.cookies, name)
			cookie.MaxAge = -1
		}
	}
}

func (srv *server) expired(cookie *http.Cookie) bool {
	now := time.Now()
	return now.After(cookie.Expires)
}

func (srv *server) wrap(fn func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		err := srv.setCookie(w, r)
		if err != nil {
			log.Printf("error retrieving cookie: %v\n", err)
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		if err := fn(w, r); err != nil {
			log.Printf("error %q: %v\n", r.URL.Path, err.Error())
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
	}
}

func (srv *server) setCookie(w http.ResponseWriter, r *http.Request) error {
	srv.mu.Lock()
	defer srv.mu.Unlock()
	cookie, err := r.Cookie(cookieName)
	if err != nil && err != http.ErrNoCookie {
		return err
	}

	if cookie != nil {
		if v, ok := srv.sessions[cookie.Value]; v == nil || !ok {
			srv.sessions[cookie.Value] = newDbFiles()
			srv.cookies[cookie.Value] = cookie
		}
		return nil
	}

	cookie = &http.Cookie{
		Name:    cookieName,
		Value:   uuid.NewV4().String(),
		Expires: time.Now().Add(24 * time.Hour),
	}
	srv.sessions[cookie.Value] = newDbFiles()
	srv.cookies[cookie.Value] = cookie
	http.SetCookie(w, cookie)
	return nil
}

func (srv *server) cookie(r *http.Request) (*http.Cookie, error) {
	srv.mu.RLock()
	defer srv.mu.RUnlock()
	cookie, err := r.Cookie(cookieName)
	if err != nil {
		return nil, err
	}

	if cookie == nil {
		return nil, http.ErrNoCookie
	}
	return srv.cookies[cookie.Value], nil
}

func (srv *server) db(r *http.Request) (*dbFiles, error) {
	srv.mu.RLock()
	defer srv.mu.RUnlock()
	cookie, err := srv.cookie(r)
	if err != nil {
		return nil, err
	}
	return srv.sessions[cookie.Value], nil
}

func (srv *server) rootHandle(w http.ResponseWriter, r *http.Request) error {
	switch r.Method {
	case http.MethodGet:
		// ok
	default:
		return fmt.Errorf("invalid request %q for /", r.Method)
	}

	crutime := time.Now().Unix()
	h := md5.New()
	io.WriteString(h, strconv.FormatInt(crutime, 10))
	token := fmt.Sprintf("%x", h.Sum(nil))

	t, err := template.New("upload").Parse(page)
	if err != nil {
		return err
	}

	return t.Execute(w, struct{ Token string }{token})
}

func (srv *server) uploadHandle(w http.ResponseWriter, r *http.Request) error {
	if r.Method != http.MethodPost {
		log.Printf("invalid request %q", r.Method)
		return fmt.Errorf("invalid request %q for /root-file-upload", r.Method)
	}

	r.ParseMultipartForm(500 << 20)
	f, handler, err := r.FormFile("upload-file")
	if err != nil {
		return err
	}
	_, err = f.Seek(0, 0)
	if err != nil {
		return err
	}

	rfile, err := rootio.NewReader(f, handler.Filename)
	if err != nil {
		return err
	}

	db, err := srv.db(r)
	if err != nil {
		return err
	}
	db.set(handler.Filename, rfile)

	var nodes []jsNode

	db.RLock()
	defer db.RUnlock()
	for k, rfile := range db.files {
		node, err := fileJsTree(rfile, k)
		if err != nil {
			return err
		}
		nodes = append(nodes, node...)
	}
	sort.Sort(jsNodes(nodes))
	return json.NewEncoder(w).Encode(nodes)
}

func (srv *server) plotH1Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)
	url := r.URL.Path[len("/plot-1d/"):]
	toks := strings.Split(url, "/")
	fname := toks[0]

	db, err := srv.db(r)
	if err != nil {
		return err
	}

	f := db.get(fname)
	obj, ok := f.Get(toks[1]) // FIXME(sbinet): handle sub-dirs
	if !ok {
		return fmt.Errorf("could not find %q in file %q", toks[1], fname)
	}

	robj, ok := obj.(yodacnv.Marshaler)
	if !ok {
		return fmt.Errorf("object %q could not be converted to hbook.H1D", toks[1])
	}
	h1d, err := rootcnv.H1D(robj)
	if err != nil {
		return err
	}

	plot, err := hplot.New()
	if err != nil {
		return err
	}
	plot.Title.Text = obj.(rootio.Named).Title()

	h, err := hplot.NewH1D(h1d)
	if err != nil {
		return err
	}
	h.Infos.Style = hplot.HInfoSummary
	h.Color = color.RGBA{255, 0, 0, 255}

	plot.Add(h, hplot.NewGrid())

	svg, err := renderSVG(plot)
	if err != nil {
		return err
	}

	return json.NewEncoder(w).Encode(string(svg))
}

func (srv *server) plotH2Handle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)

	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

func (srv *server) plotBranchHandle(w http.ResponseWriter, r *http.Request) error {
	log.Printf(">>> request: %q\n", r.URL.Path)

	return json.NewEncoder(w).Encode(map[string]string{
		"url": r.URL.Path,
	})
}

const page = `

    <title>go-hep/rootio file inspector</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
	<link rel="stylesheet" href="https://www.w3schools.com/w3css/3/w3.css">

	<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.3/themes/default/style.min.css" />

go-hep/rootio ROOT file inspector

	<form id="rootio-form" enctype="multipart/form-data" action="/root-file-upload" method="post">

		 Upload

		<input id="rootio-file" type="file" name="upload-file"/>
		<input type="hidden" name="token" value="{{.Token}}"/>
		<input type="hidden" value="upload" />
	</form>

`
<|endoftext|>


<commit_before>package twse

import (
	"encoding/csv"
	"fmt"
	"strings"
	"time"

	"github.com/toomore/gogrs/utils"
)

type QFIIS struct {
	Date time.Time
}

func (q QFIIS) URL() string {
	return fmt.Sprintf("%s%s", utils.TWSEHOST, fmt.Sprintf(utils.QFIISTOP20, q.Date.Year(), q.Date.Month(), q.Date.Day()))
}

func (q *QFIIS) Get() ([][]string, error) {
	data, _ := hCache.Get(q.URL(), false)

	csvArrayContent := strings.Split(string(data), "\n")
	for i, v := range csvArrayContent[2 : len(csvArrayContent)-1] {
		csvArrayContent[i] = strings.Replace(v, "=", "", -1)
	}

	csvReader := csv.NewReader(strings.NewReader(strings.Join(csvArrayContent[:len(csvArrayContent)-3], "\n")))
	var (
		allData [][]string
		err     error
	)
	if allData, err = csvReader.ReadAll(); err == nil {
		for _, v := range allData {
			for i, vv := range v {
				v[i] = strings.Replace(vv, ",", "", -1)
			}
		}
	}
	return allData, err
}
<commit_msg>Add note and tiny changed.<commit_after>package twse

import (
	"encoding/csv"
	"fmt"
	"strings"
	"time"

	"github.com/toomore/gogrs/utils"
)

// QFIISTOP20 取得「外資及陸資持股比率前二十名彙總表」
type QFIISTOP20 struct {
	Date time.Time
}

// URL 擷取網址
func (q QFIISTOP20) URL() string {
	return fmt.Sprintf("%s%s", utils.TWSEHOST, fmt.Sprintf(utils.QFIISTOP20, q.Date.Year(), q.Date.Month(), q.Date.Day()))
}

// Get 擷取資料
func (q *QFIISTOP20) Get() ([][]string, error) {
	data, _ := hCache.Get(q.URL(), false)

	csvArrayContent := strings.Split(string(data), "\n")
	for i, v := range csvArrayContent[2 : len(csvArrayContent)-1] {
		csvArrayContent[i] = strings.Replace(v, "=", "", -1)
	}

	csvReader := csv.NewReader(strings.NewReader(strings.Join(csvArrayContent[:len(csvArrayContent)-3], "\n")))
	return csvReader.ReadAll()
}
<|endoftext|>