<commit_before>package raidman

import (
	"bytes"
	pb "code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/amir/raidman/proto"
	"net"
	"reflect"
	"sync"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	m          sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Tags        []string
	Host        string
	State       string
	Service     string
	Metric      interface{} // Could be Int, Float32, Float64
	Description string
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if _, err = conn.Read(response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value && f.Interface() != nil {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	e, err := eventToPbEvent(event)
	if err != nil {
		return err
	}
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.m.Lock()
	defer c.m.Unlock()
	_, err = c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.m.Lock()
	defer c.m.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.m.Lock()
	c.connection.Close()
	c.m.Unlock()
}
<commit_msg>Embedding sync.Mutex<commit_after>package raidman

import (
	"bytes"
	pb "code.google.com/p/goprotobuf/proto"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/amir/raidman/proto"
	"net"
	"reflect"
	"sync"
)

type network interface {
	Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error)
}

type tcp struct{}

type udp struct{}

// Client represents a connection to a Riemann server
type Client struct {
	sync.Mutex
	net        network
	connection net.Conn
}

// An Event represents a single Riemann event
type Event struct {
	Ttl         float32
	Time        int64
	Tags        []string
	Host        string
	State       string
	Service     string
	Metric      interface{} // Could be Int, Float32, Float64
	Description string
}

// Dial establishes a connection to a Riemann server at addr, on the network
// netwrk.
//
// Known networks are "tcp", "tcp4", "tcp6", "udp", "udp4", and "udp6".
func Dial(netwrk, addr string) (c *Client, err error) {
	c = new(Client)

	var cnet network
	switch netwrk {
	case "tcp", "tcp4", "tcp6":
		cnet = new(tcp)
	case "udp", "udp4", "udp6":
		cnet = new(udp)
	default:
		return nil, fmt.Errorf("dial %q: unsupported network %q", netwrk, netwrk)
	}

	c.net = cnet
	c.connection, err = net.Dial(netwrk, addr)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func (network *tcp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	msg := &proto.Msg{}
	data, err := pb.Marshal(message)
	if err != nil {
		return msg, err
	}
	b := new(bytes.Buffer)
	if err = binary.Write(b, binary.BigEndian, uint32(len(data))); err != nil {
		return msg, err
	}
	if _, err = conn.Write(b.Bytes()); err != nil {
		return msg, err
	}
	if _, err = conn.Write(data); err != nil {
		return msg, err
	}
	var header uint32
	if err = binary.Read(conn, binary.BigEndian, &header); err != nil {
		return msg, err
	}
	response := make([]byte, header)
	if _, err = conn.Read(response); err != nil {
		return msg, err
	}
	if err = pb.Unmarshal(response, msg); err != nil {
		return msg, err
	}
	if msg.GetOk() != true {
		return msg, errors.New(msg.GetError())
	}
	return msg, nil
}

func (network *udp) Send(message *proto.Msg, conn net.Conn) (*proto.Msg, error) {
	data, err := pb.Marshal(message)
	if err != nil {
		return nil, err
	}
	if _, err = conn.Write(data); err != nil {
		return nil, err
	}

	return nil, nil
}

func eventToPbEvent(event *Event) (*proto.Event, error) {
	var e proto.Event

	t := reflect.ValueOf(&e).Elem()
	s := reflect.ValueOf(event).Elem()
	typeOfEvent := s.Type()
	for i := 0; i < s.NumField(); i++ {
		f := s.Field(i)
		value := reflect.ValueOf(f.Interface())
		if reflect.Zero(f.Type()) != value && f.Interface() != nil {
			name := typeOfEvent.Field(i).Name
			switch name {
			case "State", "Service", "Host", "Description":
				tmp := reflect.ValueOf(pb.String(value.String()))
				t.FieldByName(name).Set(tmp)
			case "Ttl":
				tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
				t.FieldByName(name).Set(tmp)
			case "Time":
				tmp := reflect.ValueOf(pb.Int64(value.Int()))
				t.FieldByName(name).Set(tmp)
			case "Tags":
				tmp := reflect.ValueOf(value.Interface().([]string))
				t.FieldByName(name).Set(tmp)
			case "Metric":
				switch reflect.TypeOf(f.Interface()).Kind() {
				case reflect.Int:
					tmp := reflect.ValueOf(pb.Int64(int64(value.Int())))
					t.FieldByName("MetricSint64").Set(tmp)
				case reflect.Float32:
					tmp := reflect.ValueOf(pb.Float32(float32(value.Float())))
					t.FieldByName("MetricF").Set(tmp)
				case reflect.Float64:
					tmp := reflect.ValueOf(pb.Float64(value.Float()))
					t.FieldByName("MetricD").Set(tmp)
				default:
					return nil, fmt.Errorf("Metric of invalid type (type %v)",
						reflect.TypeOf(f.Interface()).Kind())
				}
			}
		}
	}

	return &e, nil
}

func pbEventsToEvents(pbEvents []*proto.Event) []Event {
	var events []Event

	for _, event := range pbEvents {
		e := Event{
			State:       event.GetState(),
			Service:     event.GetService(),
			Host:        event.GetHost(),
			Description: event.GetDescription(),
			Ttl:         event.GetTtl(),
			Time:        event.GetTime(),
			Tags:        event.GetTags(),
		}
		if event.MetricF != nil {
			e.Metric = event.GetMetricF()
		} else if event.MetricD != nil {
			e.Metric = event.GetMetricD()
		} else {
			e.Metric = event.GetMetricSint64()
		}

		events = append(events, e)
	}

	return events
}

// Send sends an event to Riemann
func (c *Client) Send(event *Event) error {
	e, err := eventToPbEvent(event)
	if err != nil {
		return err
	}
	message := &proto.Msg{}
	message.Events = append(message.Events, e)
	c.Lock()
	defer c.Unlock()
	_, err = c.net.Send(message, c.connection)
	if err != nil {
		return err
	}

	return nil
}

// Query returns a list of events matched by query
func (c *Client) Query(q string) ([]Event, error) {
	switch c.net.(type) {
	case *udp:
		return nil, errors.New("Querying over UDP is not supported")
	}
	query := &proto.Query{}
	query.String_ = pb.String(q)
	message := &proto.Msg{}
	message.Query = query
	c.Lock()
	defer c.Unlock()
	response, err := c.net.Send(message, c.connection)
	if err != nil {
		return nil, err
	}
	return pbEventsToEvents(response.GetEvents()), nil
}

// Close closes the connection to Riemann
func (c *Client) Close() {
	c.Lock()
	c.connection.Close()
	c.Unlock()
}
<|endoftext|>


<commit_before>package httpcheck

import (
	"errors"
	"strconv"
	"time"
)

// A Server has a number of Scenarios to test.
type Server struct {
	Name      string "server"
	Scenarios []Scenario
}

// Test runs tests on the scenarios and tests for this server.
// It returns an error if one or more scenarios/tests has errors, or nil otherwise.
// In case there are multiple errors, the error contains the concatenated messages.
func (server Server) Test() error {
	start := time.Now()

	var allerrors []error
	for _, scenario := range server.Scenarios {
		err := scenario.Test()
		if err != nil {
			allerrors = append(allerrors, err)
		}

		// Stop testing if more time was spent than ServerTimeout
		if ServerTimeout > 0 {
			if time.Since(start) > time.Duration(ServerTimeout)*time.Second {
				allerrors = append(allerrors,
					errors.New("Tests took longer than server timeout ("+strconv.Itoa(int(ServerTimeout))+" sec)"))
				break
			}
		}
	}

	if len(allerrors) > 0 {
		errorstr := ""
		if server.Name != "" {
			errorstr = "Server " + server.Name + ": "
		}
		for i, err := range allerrors {
			if i > 0 {
				errorstr += "\n"
			}
			errorstr += err.Error()
		}
		return errors.New(errorstr)
	}
	return nil
}
<commit_msg>server: check timeout before test, to not give an extra error if last test expired the timeout<commit_after>package httpcheck

import (
	"errors"
	"strconv"
	"time"
)

// A Server has a number of Scenarios to test.
type Server struct {
	Name      string "server"
	Scenarios []Scenario
}

// Test runs tests on the scenarios and tests for this server.
// It returns an error if one or more scenarios/tests has errors, or nil otherwise.
// In case there are multiple errors, the error contains the concatenated messages.
func (server Server) Test() error {
	start := time.Now()

	var allerrors []error
	for _, scenario := range server.Scenarios {
		// Stop testing if more time was spent than ServerTimeout
		if ServerTimeout > 0 {
			if time.Since(start) > time.Duration(ServerTimeout)*time.Second {
				allerrors = append(allerrors,
					errors.New("Tests took longer than server timeout ("+strconv.Itoa(int(ServerTimeout))+" sec)"))
				break
			}
		}

		err := scenario.Test()
		if err != nil {
			allerrors = append(allerrors, err)
		}
	}

	if len(allerrors) > 0 {
		errorstr := ""
		if server.Name != "" {
			errorstr = "Server " + server.Name + ": "
		}
		for i, err := range allerrors {
			if i > 0 {
				errorstr += "\n"
			}
			errorstr += err.Error()
		}
		return errors.New(errorstr)
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 comebackfs

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/blob"
	"github.com/jacobsa/comeback/internal/fs"
	pkgfs "github.com/jacobsa/comeback/internal/fs"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/syncutil"
)

// Create a read-only file system for browsing the backup rooted by the
// supplied score. All inodes will be owned by the supplied UID/GID pair.
func NewFileSystem(
	uid uint32,
	gid uint32,
	rootScore blob.Score,
	blobStore blob.Store) (fs fuseutil.FileSystem, err error) {
	// Create the file system.
	typed := &fileSystem{
		uid:         uid,
		gid:         gid,
		blobStore:   blobStore,
		inodes:      make(map[fuseops.InodeID]*inodeRecord),
		fileHandles: make(map[fuseops.HandleID]*fileHandle),
	}

	fs = typed
	typed.mu = syncutil.NewInvariantMutex(typed.checkInvariants)

	// Set up the root inode.
	typed.Lock()
	defer typed.Unlock()

	rootEntry := &pkgfs.DirectoryEntry{
		Type:        pkgfs.TypeDirectory,
		Name:        "",
		Permissions: 0500,
		Inode:       fuseops.RootInodeID,
		Scores:      []blob.Score{rootScore},
	}

	_, err = typed.lookUpOrCreateInode(rootEntry)
	if err != nil {
		err = fmt.Errorf("Creating root inode: %v", err)
		return
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Internal
////////////////////////////////////////////////////////////////////////

type fileSystem struct {
	fuseutil.NotImplementedFileSystem

	uid uint32
	gid uint32

	blobStore blob.Store

	/////////////////////////
	// Mutable data
	/////////////////////////

	// LOCK ORDERING:
	//
	// Let FS be the file system. Define a strict partial ordering < by:
	//
	// *   For any inode I,  I < FS.
	// *   For any handle H,  H < FS.
	//
	// and follow the rule "acquire B while holding A only if A < B".
	//
	// In other words:
	//
	// *   Don't hold more than one inode or handle lock at a time.
	// *   Don't acquire an inode or handle lock before the file system lock.
	//
	// The intuition is that inode and handle locks are held for long operations,
	// but the file system lock is lightweight and must not be.
	mu syncutil.InvariantMutex

	// The inodes we currently know, along with the lookup counts. The inode IDs
	// come from the directory listings stored in GCS.
	//
	// INVARIANT: For all v, v.lookupCount > 0
	//
	// GUARDED_BY(mu)
	inodes map[fuseops.InodeID]*inodeRecord

	// The next handle ID that we will assign.
	//
	// GUARDED_BY(mu)
	nextHandleID fuseops.HandleID

	// In-flight file handles.
	//
	// INVARIANT: For each k, k < nextHandleID
	//
	// GUARDED_BY(mu)
	fileHandles map[fuseops.HandleID]*fileHandle
}

// An inode and its lookup count.
type inodeRecord struct {
	lookupCount uint64
	in          inode
}

// LOCKS_REQUIRED(fs)
func (fs *fileSystem) checkInvariants() {
	// INVARIANT: For all v, v.lookupCount > 0
	for k, v := range fs.inodes {
		if !(v.lookupCount > 0) {
			log.Fatalf("Inode %d has invalid lookupCount %d", k, v.lookupCount)
		}
	}

	// INVARIANT: For each k, k < nextHandleID
	for k, _ := range fs.fileHandles {
		if !(k < fs.nextHandleID) {
			log.Fatalf("Unexpected handle ID: %d", k)
		}
	}
}

// Given a directory entry within the file system, look up an inode for the
// entry if it already exists. If not, create and register one. In either case,
// increment the lookup count.
//
// LOCKS_REQUIRED(fs)
func (fs *fileSystem) lookUpOrCreateInode(e *fs.DirectoryEntry) (
	in inode,
	err error) {
	id := fuseops.InodeID(e.Inode)

	// Do we already have an inode with the given ID?
	if rec, ok := fs.inodes[id]; ok {
		in = rec.in
		rec.lookupCount++
		return
	}

	// Create and register one.
	in, err = createInode(e, fs.uid, fs.gid, fs.blobStore)
	if err != nil {
		err = fmt.Errorf("createInode: %v", err)
		return
	}

	fs.inodes[id] = &inodeRecord{
		lookupCount: 1,
		in:          in,
	}

	return
}

// Create an inode for the supplied directory entry. The UID and GID are
// ignored in favor of the the supplied values.
func createInode(
	e *fs.DirectoryEntry,
	uid uint32,
	gid uint32,
	blobStore blob.Store) (in inode, err error) {
	switch e.Type {
	case fs.TypeDirectory:
		// Check the score count.
		if len(e.Scores) != 1 {
			err = fmt.Errorf(
				"Unexpected score count for directory: %d",
				len(e.Scores))
			return
		}

		// Create the inode.
		in = newDirInode(
			fuseops.InodeAttributes{
				Size:  e.Size,
				Nlink: 1,
				Mode:  e.Permissions | os.ModeDir,
				Mtime: e.MTime,
				Ctime: e.MTime,
				Uid:   uid,
				Gid:   gid,
			},
			e.Scores[0],
			blobStore)

		return

	case fs.TypeFile:
		in = newFileInode(
			fuseops.InodeAttributes{
				Size:  e.Size,
				Nlink: 1,
				Mode:  e.Permissions,
				Mtime: e.MTime,
				Ctime: e.MTime,
				Uid:   uid,
				Gid:   gid,
			},
			e.Scores,
			blobStore)

		return

	default:
		err = fmt.Errorf("Don't know how to handle type %d", e.Type)
		return
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) Lock() {
	fs.mu.Lock()
}

// LOCKS_REQUIRED(fs)
func (fs *fileSystem) Unlock() {
	fs.mu.Unlock()
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) GetInodeAttributes(
	ctx context.Context,
	op *fuseops.GetInodeAttributesOp) (err error) {
	// Find the inode.
	fs.Lock()
	rec := fs.inodes[op.Inode]
	fs.Unlock()

	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	in := rec.in
	in.Lock()
	defer in.Unlock()

	// Get its attributes. We don't care how long the kernel caches them, because
	// we are immutable.
	op.Attributes = in.Attributes()
	op.AttributesExpiration = time.Now().Add(24 * time.Hour)

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) LookUpInode(
	ctx context.Context,
	op *fuseops.LookUpInodeOp) (err error) {
	// Find the parent.
	fs.Lock()
	parentRec, _ := fs.inodes[op.Parent]
	fs.Unlock()

	if parentRec == nil {
		log.Fatalf("Inode %d not found", op.Parent)
	}

	parent := parentRec.in.(*dirInode)

	// Find an entry for the child within it.
	parent.Lock()
	e, err := parent.LookUpChild(ctx, op.Name)
	parent.Unlock()

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

	if e == nil {
		err = fuse.ENOENT
		return
	}

	// Find or create the inode.
	fs.Lock()
	in, err := fs.lookUpOrCreateInode(e)
	fs.Unlock()

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

	// Fill out the response.
	in.Lock()
	defer in.Unlock()

	op.Entry.Child = fuseops.InodeID(e.Inode)
	op.Entry.Attributes = in.Attributes()
	op.Entry.AttributesExpiration = time.Now().Add(24 * time.Hour)
	op.Entry.EntryExpiration = time.Now().Add(24 * time.Hour)

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ForgetInode(
	ctx context.Context,
	op *fuseops.ForgetInodeOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	// Find the inode.
	rec := fs.inodes[op.Inode]
	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	// Decrement its lookup count.
	if rec.lookupCount < op.N {
		log.Fatalf(
			"Inode %d has lookup count %d, decrementing by %d",
			op.Inode,
			rec.lookupCount,
			op.N)
	}

	rec.lookupCount -= op.N
	if rec.lookupCount == 0 {
		delete(fs.inodes, op.Inode)
	}

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) OpenDir(
	ctx context.Context,
	op *fuseops.OpenDirOp) (err error) {
	// Nothing interesting to do since we don't use directory handles.
	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReadDir(
	ctx context.Context,
	op *fuseops.ReadDirOp) (err error) {
	// Find the inode.
	fs.Lock()
	rec, _ := fs.inodes[op.Inode]
	fs.Unlock()

	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	d := rec.in.(*dirInode)

	// Read.
	d.Lock()
	err = d.Read(ctx, op)
	d.Unlock()

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) OpenFile(
	ctx context.Context,
	op *fuseops.OpenFileOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	// Find the inode.
	rec, _ := fs.inodes[op.Inode]
	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	f := rec.in.(*fileInode)

	// Create the handle.
	fh := newFileHandle(f.Scores(), fs.blobStore)

	op.Handle = fs.nextHandleID
	fs.nextHandleID++
	fs.fileHandles[op.Handle] = fh

	// Allow the kernel to cache file contents.
	op.KeepPageCache = true

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReadFile(
	ctx context.Context,
	op *fuseops.ReadFileOp) (err error) {
	// Find the handle.
	fs.Lock()
	fh, ok := fs.fileHandles[op.Handle]
	fs.Unlock()

	if !ok {
		log.Fatalf("Handle %d not found", op.Handle)
	}

	// Read from it.
	fh.Lock()
	op.BytesRead, err = fh.ReadAt(ctx, op.Dst, op.Offset)
	fh.Unlock()

	// We're not supposed to return io.EOF.
	if err == io.EOF {
		err = nil
	}

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReleaseFileHandle(
	ctx context.Context,
	op *fuseops.ReleaseFileHandleOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	fh := fs.fileHandles[op.Handle]
	fh.Destroy()
	delete(fs.fileHandles, op.Handle)

	return
}
<commit_msg>Updated createInode.<commit_after>// Copyright 2015 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 comebackfs

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	"golang.org/x/net/context"

	"github.com/jacobsa/comeback/internal/blob"
	"github.com/jacobsa/comeback/internal/fs"
	pkgfs "github.com/jacobsa/comeback/internal/fs"
	"github.com/jacobsa/fuse"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/fuse/fuseutil"
	"github.com/jacobsa/syncutil"
)

// Create a read-only file system for browsing the backup rooted by the
// supplied score. All inodes will be owned by the supplied UID/GID pair.
func NewFileSystem(
	uid uint32,
	gid uint32,
	rootScore blob.Score,
	blobStore blob.Store) (fs fuseutil.FileSystem, err error) {
	// Create the file system.
	typed := &fileSystem{
		uid:         uid,
		gid:         gid,
		blobStore:   blobStore,
		inodes:      make(map[fuseops.InodeID]*inodeRecord),
		fileHandles: make(map[fuseops.HandleID]*fileHandle),
	}

	fs = typed
	typed.mu = syncutil.NewInvariantMutex(typed.checkInvariants)

	// Set up the root inode.
	typed.Lock()
	defer typed.Unlock()

	rootEntry := &pkgfs.DirectoryEntry{
		Type:        pkgfs.TypeDirectory,
		Name:        "",
		Permissions: 0500,
		Inode:       fuseops.RootInodeID,
		Scores:      []blob.Score{rootScore},
	}

	_, err = typed.lookUpOrCreateInode(rootEntry)
	if err != nil {
		err = fmt.Errorf("Creating root inode: %v", err)
		return
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Internal
////////////////////////////////////////////////////////////////////////

type fileSystem struct {
	fuseutil.NotImplementedFileSystem

	uid uint32
	gid uint32

	blobStore blob.Store

	/////////////////////////
	// Mutable data
	/////////////////////////

	// LOCK ORDERING:
	//
	// Let FS be the file system. Define a strict partial ordering < by:
	//
	// *   For any inode I,  I < FS.
	// *   For any handle H,  H < FS.
	//
	// and follow the rule "acquire B while holding A only if A < B".
	//
	// In other words:
	//
	// *   Don't hold more than one inode or handle lock at a time.
	// *   Don't acquire an inode or handle lock before the file system lock.
	//
	// The intuition is that inode and handle locks are held for long operations,
	// but the file system lock is lightweight and must not be.
	mu syncutil.InvariantMutex

	// The inodes we currently know, along with the lookup counts. The inode IDs
	// come from the directory listings stored in GCS.
	//
	// INVARIANT: For all v, v.lookupCount > 0
	//
	// GUARDED_BY(mu)
	inodes map[fuseops.InodeID]*inodeRecord

	// The next handle ID that we will assign.
	//
	// GUARDED_BY(mu)
	nextHandleID fuseops.HandleID

	// In-flight file handles.
	//
	// INVARIANT: For each k, k < nextHandleID
	//
	// GUARDED_BY(mu)
	fileHandles map[fuseops.HandleID]*fileHandle
}

// An inode and its lookup count.
type inodeRecord struct {
	lookupCount uint64
	in          inode
}

// LOCKS_REQUIRED(fs)
func (fs *fileSystem) checkInvariants() {
	// INVARIANT: For all v, v.lookupCount > 0
	for k, v := range fs.inodes {
		if !(v.lookupCount > 0) {
			log.Fatalf("Inode %d has invalid lookupCount %d", k, v.lookupCount)
		}
	}

	// INVARIANT: For each k, k < nextHandleID
	for k, _ := range fs.fileHandles {
		if !(k < fs.nextHandleID) {
			log.Fatalf("Unexpected handle ID: %d", k)
		}
	}
}

// Given a directory entry within the file system, look up an inode for the
// entry if it already exists. If not, create and register one. In either case,
// increment the lookup count.
//
// LOCKS_REQUIRED(fs)
func (fs *fileSystem) lookUpOrCreateInode(e *fs.DirectoryEntry) (
	in inode,
	err error) {
	id := fuseops.InodeID(e.Inode)

	// Do we already have an inode with the given ID?
	if rec, ok := fs.inodes[id]; ok {
		in = rec.in
		rec.lookupCount++
		return
	}

	// Create and register one.
	in, err = createInode(e, fs.uid, fs.gid, fs.blobStore)
	if err != nil {
		err = fmt.Errorf("createInode: %v", err)
		return
	}

	fs.inodes[id] = &inodeRecord{
		lookupCount: 1,
		in:          in,
	}

	return
}

// Create an inode for the supplied directory entry. The UID and GID are
// ignored in favor of the the supplied values.
func createInode(
	e *fs.DirectoryEntry,
	uid uint32,
	gid uint32,
	blobStore blob.Store) (in inode, err error) {
	switch e.Type {
	case fs.TypeDirectory:
		// Check the score count.
		if len(e.Scores) != 1 {
			err = fmt.Errorf(
				"Unexpected score count for directory: %d",
				len(e.Scores))
			return
		}

		// Create the inode.
		in = newDirInode(
			fuseops.InodeAttributes{
				Size:  e.Size,
				Nlink: 1,
				Mode:  e.Permissions | os.ModeDir,
				Mtime: e.MTime,
				Ctime: e.MTime,
				Uid:   uid,
				Gid:   gid,
			},
			e.Scores[0],
			blobStore)

		return

	case fs.TypeFile:
		in = newFileInode(
			fuseops.InodeAttributes{
				Size:  e.Size,
				Nlink: 1,
				Mode:  e.Permissions,
				Mtime: e.MTime,
				Ctime: e.MTime,
				Uid:   uid,
				Gid:   gid,
			},
			e.Scores,
			blobStore)

		return

	case fs.TypeSymlink:
		in = newSymlinkInode(
			fuseops.InodeAttributes{
				Size:  e.Size,
				Nlink: 1,
				Mode:  e.Permissions | os.ModeSymlink,
				Mtime: e.MTime,
				Ctime: e.MTime,
				Uid:   uid,
				Gid:   gid,
			},
			e.Target)

		return

	default:
		err = fmt.Errorf("Don't know how to handle type %d", e.Type)
		return
	}
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) Lock() {
	fs.mu.Lock()
}

// LOCKS_REQUIRED(fs)
func (fs *fileSystem) Unlock() {
	fs.mu.Unlock()
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) GetInodeAttributes(
	ctx context.Context,
	op *fuseops.GetInodeAttributesOp) (err error) {
	// Find the inode.
	fs.Lock()
	rec := fs.inodes[op.Inode]
	fs.Unlock()

	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	in := rec.in
	in.Lock()
	defer in.Unlock()

	// Get its attributes. We don't care how long the kernel caches them, because
	// we are immutable.
	op.Attributes = in.Attributes()
	op.AttributesExpiration = time.Now().Add(24 * time.Hour)

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) LookUpInode(
	ctx context.Context,
	op *fuseops.LookUpInodeOp) (err error) {
	// Find the parent.
	fs.Lock()
	parentRec, _ := fs.inodes[op.Parent]
	fs.Unlock()

	if parentRec == nil {
		log.Fatalf("Inode %d not found", op.Parent)
	}

	parent := parentRec.in.(*dirInode)

	// Find an entry for the child within it.
	parent.Lock()
	e, err := parent.LookUpChild(ctx, op.Name)
	parent.Unlock()

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

	if e == nil {
		err = fuse.ENOENT
		return
	}

	// Find or create the inode.
	fs.Lock()
	in, err := fs.lookUpOrCreateInode(e)
	fs.Unlock()

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

	// Fill out the response.
	in.Lock()
	defer in.Unlock()

	op.Entry.Child = fuseops.InodeID(e.Inode)
	op.Entry.Attributes = in.Attributes()
	op.Entry.AttributesExpiration = time.Now().Add(24 * time.Hour)
	op.Entry.EntryExpiration = time.Now().Add(24 * time.Hour)

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ForgetInode(
	ctx context.Context,
	op *fuseops.ForgetInodeOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	// Find the inode.
	rec := fs.inodes[op.Inode]
	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	// Decrement its lookup count.
	if rec.lookupCount < op.N {
		log.Fatalf(
			"Inode %d has lookup count %d, decrementing by %d",
			op.Inode,
			rec.lookupCount,
			op.N)
	}

	rec.lookupCount -= op.N
	if rec.lookupCount == 0 {
		delete(fs.inodes, op.Inode)
	}

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) OpenDir(
	ctx context.Context,
	op *fuseops.OpenDirOp) (err error) {
	// Nothing interesting to do since we don't use directory handles.
	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReadDir(
	ctx context.Context,
	op *fuseops.ReadDirOp) (err error) {
	// Find the inode.
	fs.Lock()
	rec, _ := fs.inodes[op.Inode]
	fs.Unlock()

	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	d := rec.in.(*dirInode)

	// Read.
	d.Lock()
	err = d.Read(ctx, op)
	d.Unlock()

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) OpenFile(
	ctx context.Context,
	op *fuseops.OpenFileOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	// Find the inode.
	rec, _ := fs.inodes[op.Inode]
	if rec == nil {
		log.Fatalf("Inode %d not found", op.Inode)
	}

	f := rec.in.(*fileInode)

	// Create the handle.
	fh := newFileHandle(f.Scores(), fs.blobStore)

	op.Handle = fs.nextHandleID
	fs.nextHandleID++
	fs.fileHandles[op.Handle] = fh

	// Allow the kernel to cache file contents.
	op.KeepPageCache = true

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReadFile(
	ctx context.Context,
	op *fuseops.ReadFileOp) (err error) {
	// Find the handle.
	fs.Lock()
	fh, ok := fs.fileHandles[op.Handle]
	fs.Unlock()

	if !ok {
		log.Fatalf("Handle %d not found", op.Handle)
	}

	// Read from it.
	fh.Lock()
	op.BytesRead, err = fh.ReadAt(ctx, op.Dst, op.Offset)
	fh.Unlock()

	// We're not supposed to return io.EOF.
	if err == io.EOF {
		err = nil
	}

	return
}

// LOCKS_EXCLUDED(fs)
func (fs *fileSystem) ReleaseFileHandle(
	ctx context.Context,
	op *fuseops.ReleaseFileHandleOp) (err error) {
	fs.Lock()
	defer fs.Unlock()

	fh := fs.fileHandles[op.Handle]
	fh.Destroy()
	delete(fs.fileHandles, op.Handle)

	return
}
<|endoftext|>


<commit_before>//go:build darwin || freebsd || linux
// +build darwin freebsd linux

package fuse

import (
	"context"
	"os"

	"github.com/restic/restic/internal/debug"

	"bazil.org/fuse"
	"bazil.org/fuse/fs"
)

// ensure that *DirSnapshots implements these interfaces
var _ = fs.HandleReadDirAller(&MetaDir{})
var _ = fs.NodeStringLookuper(&MetaDir{})

// MetaDir is a fuse directory which contains other directories.
type MetaDir struct {
	inode   uint64
	root    *Root
	entries map[string]fs.Node
}

// NewMetaDir returns a new meta dir.
func NewMetaDir(root *Root, inode uint64, entries map[string]fs.Node) *MetaDir {
	debug.Log("new meta dir with %d entries, inode %d", len(entries), inode)

	return &MetaDir{
		root:    root,
		inode:   inode,
		entries: entries,
	}
}

// Attr returns the attributes for the root node.
func (d *MetaDir) Attr(ctx context.Context, attr *fuse.Attr) error {
	attr.Inode = d.inode
	attr.Mode = os.ModeDir | 0555
	attr.Uid = d.root.uid
	attr.Gid = d.root.gid

	debug.Log("attr: %v", attr)
	return nil
}

// ReadDirAll returns all entries of the root node.
func (d *MetaDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
	debug.Log("ReadDirAll()")
	items := []fuse.Dirent{
		{
			Inode: d.inode,
			Name:  ".",
			Type:  fuse.DT_Dir,
		},
		{
			Inode: d.root.inode,
			Name:  "..",
			Type:  fuse.DT_Dir,
		},
	}

	for name := range d.entries {
		items = append(items, fuse.Dirent{
			Inode: fs.GenerateDynamicInode(d.inode, name),
			Name:  name,
			Type:  fuse.DT_Dir,
		})
	}

	return items, nil
}

// Lookup returns a specific entry from the root node.
func (d *MetaDir) Lookup(ctx context.Context, name string) (fs.Node, error) {
	debug.Log("Lookup(%s)", name)

	if dir, ok := d.entries[name]; ok {
		return dir, nil
	}

	return nil, fuse.ENOENT
}
<commit_msg>fuse: remove unused MetaDir<commit_after><|endoftext|>


<commit_before>package gio

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestEqualFilesError(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/nope.txt", "./testdata/somefile.txt"},
		{"./testdata/somefile.txt", "./testdata/nope.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.Error(t, err)
		require.False(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.Error(t, err)
		require.False(t, equalContents)
	}
}

func TestEqualFiles(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/somefile.txt", "./testdata/somefile_copy.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equalContents)
	}
}
func TestEqualFileCointents(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/somefile.txt", "./testdata/somefile_copy_perm.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.NoError(t, err)
		require.False(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equalContents)
	}
}
<commit_msg>chore: fmt<commit_after>package gio

import (
	"testing"

	"github.com/stretchr/testify/require"
)

func TestEqualFilesError(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/nope.txt", "./testdata/somefile.txt"},
		{"./testdata/somefile.txt", "./testdata/nope.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.Error(t, err)
		require.False(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.Error(t, err)
		require.False(t, equalContents)
	}
}

func TestEqualFiles(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/somefile.txt", "./testdata/somefile_copy.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equalContents)
	}
}

func TestEqualFileCointents(t *testing.T) {
	tests := []struct {
		a string
		b string
	}{
		{"./testdata/somefile.txt", "./testdata/somefile_copy_perm.txt"},
	}
	for _, test := range tests {
		equal, err := EqualFiles(test.a, test.b)
		require.NoError(t, err)
		require.False(t, equal)

		equalContents, err := EqualFileContents(test.a, test.b)
		require.NoError(t, err)
		require.True(t, equalContents)
	}
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail

import (
	"bytes"
	"encoding/json"
	"expvar"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

const timeoutMultiplier = 3

type TestServer struct {
	*Server

	tb testing.TB

	// Set this to change the poll deadline when using DoOrTimeout within this TestServer.
	DoOrTimeoutDeadline time.Duration
}

// TestMakeServer makes a new TestServer for use in tests, but does not start
// the server.  If an error occurs during creation, a testing.Fatal is issued.
func TestMakeServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) *TestServer {
	tb.Helper()
	w, err := watcher.NewLogWatcher(pollInterval, enableFsNotify)
	if err != nil {
		tb.Fatal(err)
	}

	expvar.Get("lines_total").(*expvar.Int).Set(0)
	expvar.Get("log_count").(*expvar.Int).Set(0)
	expvar.Get("log_rotations_total").(*expvar.Map).Init()
	expvar.Get("prog_loads_total").(*expvar.Map).Init()

	m, err := New(metrics.NewStore(), w, options...)
	if err != nil {
		tb.Fatal(err)
	}
	return &TestServer{Server: m, tb: tb}
}

// TestStartServer creates a new TestServer and starts it running.  It
// returns the server, and a cleanup function.
func TestStartServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) (*TestServer, func()) {
	tb.Helper()
	options = append(options, BindAddress("", "0"))

	m := TestMakeServer(tb, pollInterval, enableFsNotify, options...)
	return m, m.Start()
}

// Start starts the TestServer and returns a cleanup function.
func (m *TestServer) Start() func() {
	m.tb.Helper()
	errc := make(chan error, 1)
	go func() {
		err := m.Run()
		errc <- err
	}()

	glog.Infof("check that server is listening")
	count := 0
	for _, err := net.DialTimeout("tcp", m.Addr(), 10*time.Millisecond*timeoutMultiplier); err != nil && count < 10; count++ {
		glog.Infof("err: %s, retrying to dial %s", err, m.Addr())
		time.Sleep(100 * time.Millisecond * timeoutMultiplier)
	}
	if count >= 10 {
		m.tb.Fatal("server wasn't listening after 10 attempts")
	}

	return func() {
		err := m.Close(true)
		if err != nil {
			m.tb.Fatal(err)
		}

		select {
		case err = <-errc:
		case <-time.After(5 * time.Second):
			buf := make([]byte, 1<<16)
			n := runtime.Stack(buf, true)
			fmt.Fprintf(os.Stderr, "%s", buf[0:n])
			m.tb.Fatal("timeout waiting for shutdown")
		}
		if err != nil {
			m.tb.Fatal(err)
		}
	}
}

// TestGetMetric fetches the expvar metrics from the Server at addr, and
// returns the value of one named name.  Callers are responsible for type
// assertions on the returned value.
func TestGetMetric(tb testing.TB, addr, name string) interface{} {
	tb.Helper()
	uri := fmt.Sprintf("http://%s/debug/vars", addr)
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err := client.Get(uri)
	if err != nil {
		tb.Fatal(err)
	}
	buf := new(bytes.Buffer)
	n, err := buf.ReadFrom(resp.Body)
	resp.Body.Close()
	testutil.FatalIfErr(tb, err)
	glog.V(2).Infof("TestGetMetric: http client read %d bytes from debug/vars", n)
	var r map[string]interface{}
	if err := json.Unmarshal(buf.Bytes(), &r); err != nil {
		tb.Fatalf("%s: body was %s", err, buf.String())
	}
	glog.Infof("TestGetMetric: returned value for %s: %v", name, r[name])
	return r[name]
}

// TestMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func TestMetricDelta(a, b interface{}) float64 {
	if a == nil {
		a = 0.
	}
	if b == nil {
		b = 0.
	}
	return a.(float64) - b.(float64)
}

// ExpectMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func ExpectMetricDelta(tb testing.TB, a, b interface{}, want float64) {
	tb.Helper()
	delta := TestMetricDelta(a, b)
	if delta != want {
		tb.Errorf("Unexpected delta: got %v - %v = %g, want %g", a, b, delta, want)
	}
}

// ExpectMetricDeltaWithDeadline returns a deferrable function which tests if the metric with name has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func (ts *TestServer) ExpectMetricDeltaWithDeadline(name string, want float64) func() {
	ts.tb.Helper()
	deadline := ts.DoOrTimeoutDeadline
	if deadline == 0 {
		deadline = time.Minute
	}
	start := TestGetMetric(ts.tb, ts.Addr(), name)
	check := func() (bool, error) {
		ts.tb.Helper()
		now := TestGetMetric(ts.tb, ts.Addr(), name)
		return TestMetricDelta(now, start) == want, nil
	}
	return func() {
		ts.tb.Helper()
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			ts.tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(ts.tb, ts.Addr(), name)
			delta := TestMetricDelta(now, start)
			ts.tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now, start, delta, want)
		}
	}
}

// ExpectMapMetricDeltaWithDeadline returns a deferrable function which tests if the map metric with name and key has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func (ts *TestServer) ExpectMapMetricDeltaWithDeadline(name, key string, want float64) func() {
	ts.tb.Helper()
	deadline := ts.DoOrTimeoutDeadline
	if deadline == 0 {
		deadline = time.Minute
	}
	start := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
	check := func() (bool, error) {
		ts.tb.Helper()
		now := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
		return TestMetricDelta(now[key], start[key]) == want, nil
	}
	return func() {
		ts.tb.Helper()
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			ts.tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
			delta := TestMetricDelta(now[key], start[key])
			ts.tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now[key], start[key], delta, want)
		}
	}
}
<commit_msg>REorder TestMakeServer init to match mtail_test.go<commit_after>// Copyright 2019 Google Inc. All Rights Reserved.
// This file is available under the Apache license.
// +build integration

package mtail

import (
	"bytes"
	"encoding/json"
	"expvar"
	"fmt"
	"net"
	"net/http"
	"os"
	"runtime"
	"testing"
	"time"

	"github.com/golang/glog"
	"github.com/google/mtail/internal/metrics"
	"github.com/google/mtail/internal/testutil"
	"github.com/google/mtail/internal/watcher"
)

const timeoutMultiplier = 3

type TestServer struct {
	*Server

	tb testing.TB

	// Set this to change the poll deadline when using DoOrTimeout within this TestServer.
	DoOrTimeoutDeadline time.Duration
}

// TestMakeServer makes a new TestServer for use in tests, but does not start
// the server.  If an error occurs during creation, a testing.Fatal is issued.
func TestMakeServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) *TestServer {
	tb.Helper()

	expvar.Get("lines_total").(*expvar.Int).Set(0)
	expvar.Get("log_count").(*expvar.Int).Set(0)
	expvar.Get("log_rotations_total").(*expvar.Map).Init()
	expvar.Get("prog_loads_total").(*expvar.Map).Init()

	w, err := watcher.NewLogWatcher(pollInterval, enableFsNotify)
	testutil.FatalIfErr(tb, err)
	m, err := New(metrics.NewStore(), w, options...)
	if err != nil {
		tb.Fatal(err)
	}
	return &TestServer{Server: m, tb: tb}
}

// TestStartServer creates a new TestServer and starts it running.  It
// returns the server, and a cleanup function.
func TestStartServer(tb testing.TB, pollInterval time.Duration, enableFsNotify bool, options ...func(*Server) error) (*TestServer, func()) {
	tb.Helper()
	options = append(options, BindAddress("", "0"))

	m := TestMakeServer(tb, pollInterval, enableFsNotify, options...)
	return m, m.Start()
}

// Start starts the TestServer and returns a cleanup function.
func (m *TestServer) Start() func() {
	m.tb.Helper()
	errc := make(chan error, 1)
	go func() {
		err := m.Run()
		errc <- err
	}()

	glog.Infof("check that server is listening")
	count := 0
	for _, err := net.DialTimeout("tcp", m.Addr(), 10*time.Millisecond*timeoutMultiplier); err != nil && count < 10; count++ {
		glog.Infof("err: %s, retrying to dial %s", err, m.Addr())
		time.Sleep(100 * time.Millisecond * timeoutMultiplier)
	}
	if count >= 10 {
		m.tb.Fatal("server wasn't listening after 10 attempts")
	}

	return func() {
		err := m.Close(true)
		if err != nil {
			m.tb.Fatal(err)
		}

		select {
		case err = <-errc:
		case <-time.After(5 * time.Second):
			buf := make([]byte, 1<<16)
			n := runtime.Stack(buf, true)
			fmt.Fprintf(os.Stderr, "%s", buf[0:n])
			m.tb.Fatal("timeout waiting for shutdown")
		}
		if err != nil {
			m.tb.Fatal(err)
		}
	}
}

// TestGetMetric fetches the expvar metrics from the Server at addr, and
// returns the value of one named name.  Callers are responsible for type
// assertions on the returned value.
func TestGetMetric(tb testing.TB, addr, name string) interface{} {
	tb.Helper()
	uri := fmt.Sprintf("http://%s/debug/vars", addr)
	client := &http.Client{
		Timeout: 5 * time.Second,
	}
	resp, err := client.Get(uri)
	if err != nil {
		tb.Fatal(err)
	}
	buf := new(bytes.Buffer)
	n, err := buf.ReadFrom(resp.Body)
	resp.Body.Close()
	testutil.FatalIfErr(tb, err)
	glog.V(2).Infof("TestGetMetric: http client read %d bytes from debug/vars", n)
	var r map[string]interface{}
	if err := json.Unmarshal(buf.Bytes(), &r); err != nil {
		tb.Fatalf("%s: body was %s", err, buf.String())
	}
	glog.Infof("TestGetMetric: returned value for %s: %v", name, r[name])
	return r[name]
}

// TestMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func TestMetricDelta(a, b interface{}) float64 {
	if a == nil {
		a = 0.
	}
	if b == nil {
		b = 0.
	}
	return a.(float64) - b.(float64)
}

// ExpectMetricDelta checks to see if the difference between a and b is want;
// it assumes both values are float64s that came from a TestGetMetric.
func ExpectMetricDelta(tb testing.TB, a, b interface{}, want float64) {
	tb.Helper()
	delta := TestMetricDelta(a, b)
	if delta != want {
		tb.Errorf("Unexpected delta: got %v - %v = %g, want %g", a, b, delta, want)
	}
}

// ExpectMetricDeltaWithDeadline returns a deferrable function which tests if the metric with name has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func (ts *TestServer) ExpectMetricDeltaWithDeadline(name string, want float64) func() {
	ts.tb.Helper()
	deadline := ts.DoOrTimeoutDeadline
	if deadline == 0 {
		deadline = time.Minute
	}
	start := TestGetMetric(ts.tb, ts.Addr(), name)
	check := func() (bool, error) {
		ts.tb.Helper()
		now := TestGetMetric(ts.tb, ts.Addr(), name)
		return TestMetricDelta(now, start) == want, nil
	}
	return func() {
		ts.tb.Helper()
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			ts.tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(ts.tb, ts.Addr(), name)
			delta := TestMetricDelta(now, start)
			ts.tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now, start, delta, want)
		}
	}
}

// ExpectMapMetricDeltaWithDeadline returns a deferrable function which tests if the map metric with name and key has changed by delta within the given deadline, once the function begins.  Before returning, it fetches the original value for comparison.
func (ts *TestServer) ExpectMapMetricDeltaWithDeadline(name, key string, want float64) func() {
	ts.tb.Helper()
	deadline := ts.DoOrTimeoutDeadline
	if deadline == 0 {
		deadline = time.Minute
	}
	start := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
	check := func() (bool, error) {
		ts.tb.Helper()
		now := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
		return TestMetricDelta(now[key], start[key]) == want, nil
	}
	return func() {
		ts.tb.Helper()
		ok, err := testutil.DoOrTimeout(check, deadline, 10*time.Millisecond)
		if err != nil {
			ts.tb.Fatal(err)
		}
		if !ok {
			now := TestGetMetric(ts.tb, ts.Addr(), name).(map[string]interface{})
			delta := TestMetricDelta(now[key], start[key])
			ts.tb.Errorf("Did not see delta by deadline: got %v - %v = %g, want %g", now[key], start[key], delta, want)
		}
	}
}
<|endoftext|>


<commit_before>package tl

import "github.com/sirupsen/logrus"

type Stash chan Match

var (
	stashMatchChan Stash
)

func GetStashChan() Stash {
	if stashMatchChan == nil {
		stashMatchChan = make(chan Match)
	}
	return stashMatchChan
}

func (s Stash) Put(m Match) {
	s <- m
}

func (s Stash) Run(ircs ...IRC) {
	for {
		select {
		case match := <-s:
			vs, err := GetFinalMatchRes(match.detailURL, match.vs.P1, match.vs.P2)
			if err != nil {
				logrus.Warnf("update message: %q", err)
				continue
			}
			match.vs = vs
			match.timeCountingDown = "已结束"
			match.isOnGoing = false
			msg := match.GetMDMatchInfo()
			for _, irc := range ircs {
				content := irc.ResolveMessage([]string{msg})
				if err := irc.Send(content); err != nil {
					logrus.Errorf("send FIN message: %q", err)
					continue
				}
			}
		}
	}
}
<commit_msg>internal/tl: fix empty terminated versus info ifmatch parser rule is not matched<commit_after>package tl

import "github.com/sirupsen/logrus"

type Stash chan Match

var (
	stashMatchChan Stash
)

func GetStashChan() Stash {
	if stashMatchChan == nil {
		stashMatchChan = make(chan Match)
	}
	return stashMatchChan
}

func (s Stash) Put(m Match) {
	s <- m
}

func (s Stash) Run(ircs ...IRC) {
	for {
		select {
		case match := <-s:
			if match.vs.P1 == "" || match.vs.P2 == "" {
				logrus.Warnf("match series parser rules not set")
				continue
			}
			vs, err := GetFinalMatchRes(match.detailURL, match.vs.P1, match.vs.P2)
			if err != nil {
				logrus.Warnf("update message: %q", err)
				continue
			}
			match.vs = vs
			match.timeCountingDown = "已结束"
			match.isOnGoing = false
			msg := match.GetMDMatchInfo()
			for _, irc := range ircs {
				content := irc.ResolveMessage([]string{msg})
				if err := irc.Send(content); err != nil {
					logrus.Errorf("send FIN message: %q", err)
					continue
				}
			}
		}
	}
}
<|endoftext|>


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

// Package jws provides encoding and decoding utilities for
// signed JWS messages.
package jws // import "golang.org/x/oauth2/jws"

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"
)

// ClaimSet contains information about the JWT signature including the
// permissions being requested (scopes), the target of the token, the issuer,
// the time the token was issued, and the lifetime of the token.
type ClaimSet struct {
	Iss   string `json:"iss"`             // email address of the client_id of the application making the access token request
	Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
	Aud   string `json:"aud"`             // descriptor of the intended target of the assertion (Optional).
	Exp   int64  `json:"exp"`             // the expiration time of the assertion (seconds since Unix epoch)
	Iat   int64  `json:"iat"`             // the time the assertion was issued (seconds since Unix epoch)
	Typ   string `json:"typ,omitempty"`   // token type (Optional).

	// Email for which the application is requesting delegated access (Optional).
	Sub string `json:"sub,omitempty"`

	// The old name of Sub. Client keeps setting Prn to be
	// complaint with legacy OAuth 2.0 providers. (Optional)
	Prn string `json:"prn,omitempty"`

	// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
	// This array is marshalled using custom code (see (c *ClaimSet) encode()).
	PrivateClaims map[string]interface{} `json:"-"`
}

func (c *ClaimSet) encode() (string, error) {
	// Reverting time back for machines whose time is not perfectly in sync.
	// If client machine's time is in the future according
	// to Google servers, an access token will not be issued.
	now := time.Now().Add(-10 * time.Second)
	if c.Iat == 0 {
		c.Iat = now.Unix()
	}
	if c.Exp == 0 {
		c.Exp = now.Add(time.Hour).Unix()
	}
	if c.Exp < c.Iat {
		return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
	}

	b, err := json.Marshal(c)
	if err != nil {
		return "", err
	}

	if len(c.PrivateClaims) == 0 {
		return base64Encode(b), nil
	}

	// Marshal private claim set and then append it to b.
	prv, err := json.Marshal(c.PrivateClaims)
	if err != nil {
		return "", fmt.Errorf("jws: invalid map of private claims %v", c.PrivateClaims)
	}

	// Concatenate public and private claim JSON objects.
	if !bytes.HasSuffix(b, []byte{'}'}) {
		return "", fmt.Errorf("jws: invalid JSON %s", b)
	}
	if !bytes.HasPrefix(prv, []byte{'{'}) {
		return "", fmt.Errorf("jws: invalid JSON %s", prv)
	}
	b[len(b)-1] = ','         // Replace closing curly brace with a comma.
	b = append(b, prv[1:]...) // Append private claims.
	return base64Encode(b), nil
}

// Header represents the header for the signed JWS payloads.
type Header struct {
	// The algorithm used for signature.
	Algorithm string `json:"alg"`

	// Represents the token type.
	Typ string `json:"typ"`
}

func (h *Header) encode() (string, error) {
	b, err := json.Marshal(h)
	if err != nil {
		return "", err
	}
	return base64Encode(b), nil
}

// Decode decodes a claim set from a JWS payload.
func Decode(payload string) (*ClaimSet, error) {
	// decode returned id token to get expiry
	s := strings.Split(payload, ".")
	if len(s) < 2 {
		// TODO(jbd): Provide more context about the error.
		return nil, errors.New("jws: invalid token received")
	}
	decoded, err := base64Decode(s[1])
	if err != nil {
		return nil, err
	}
	c := &ClaimSet{}
	err = json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c)
	return c, err
}

// Encode encodes a signed JWS with provided header and claim set.
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) {
	head, err := header.encode()
	if err != nil {
		return "", err
	}
	cs, err := c.encode()
	if err != nil {
		return "", err
	}
	ss := fmt.Sprintf("%s.%s", head, cs)
	h := sha256.New()
	h.Write([]byte(ss))
	b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
	if err != nil {
		return "", err
	}
	sig := base64Encode(b)
	return fmt.Sprintf("%s.%s", ss, sig), nil
}

// base64Encode returns and Base64url encoded version of the input string with any
// trailing "=" stripped.
func base64Encode(b []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

// base64Decode decodes the Base64url encoded string
func base64Decode(s string) ([]byte, error) {
	// add back missing padding
	switch len(s) % 4 {
	case 2:
		s += "=="
	case 3:
		s += "="
	}
	return base64.URLEncoding.DecodeString(s)
}
<commit_msg>jws: add EncodeWithSigner function.<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package jws provides encoding and decoding utilities for
// signed JWS messages.
package jws // import "golang.org/x/oauth2/jws"

import (
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"
)

// ClaimSet contains information about the JWT signature including the
// permissions being requested (scopes), the target of the token, the issuer,
// the time the token was issued, and the lifetime of the token.
type ClaimSet struct {
	Iss   string `json:"iss"`             // email address of the client_id of the application making the access token request
	Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
	Aud   string `json:"aud"`             // descriptor of the intended target of the assertion (Optional).
	Exp   int64  `json:"exp"`             // the expiration time of the assertion (seconds since Unix epoch)
	Iat   int64  `json:"iat"`             // the time the assertion was issued (seconds since Unix epoch)
	Typ   string `json:"typ,omitempty"`   // token type (Optional).

	// Email for which the application is requesting delegated access (Optional).
	Sub string `json:"sub,omitempty"`

	// The old name of Sub. Client keeps setting Prn to be
	// complaint with legacy OAuth 2.0 providers. (Optional)
	Prn string `json:"prn,omitempty"`

	// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
	// This array is marshalled using custom code (see (c *ClaimSet) encode()).
	PrivateClaims map[string]interface{} `json:"-"`
}

func (c *ClaimSet) encode() (string, error) {
	// Reverting time back for machines whose time is not perfectly in sync.
	// If client machine's time is in the future according
	// to Google servers, an access token will not be issued.
	now := time.Now().Add(-10 * time.Second)
	if c.Iat == 0 {
		c.Iat = now.Unix()
	}
	if c.Exp == 0 {
		c.Exp = now.Add(time.Hour).Unix()
	}
	if c.Exp < c.Iat {
		return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
	}

	b, err := json.Marshal(c)
	if err != nil {
		return "", err
	}

	if len(c.PrivateClaims) == 0 {
		return base64Encode(b), nil
	}

	// Marshal private claim set and then append it to b.
	prv, err := json.Marshal(c.PrivateClaims)
	if err != nil {
		return "", fmt.Errorf("jws: invalid map of private claims %v", c.PrivateClaims)
	}

	// Concatenate public and private claim JSON objects.
	if !bytes.HasSuffix(b, []byte{'}'}) {
		return "", fmt.Errorf("jws: invalid JSON %s", b)
	}
	if !bytes.HasPrefix(prv, []byte{'{'}) {
		return "", fmt.Errorf("jws: invalid JSON %s", prv)
	}
	b[len(b)-1] = ','         // Replace closing curly brace with a comma.
	b = append(b, prv[1:]...) // Append private claims.
	return base64Encode(b), nil
}

// Header represents the header for the signed JWS payloads.
type Header struct {
	// The algorithm used for signature.
	Algorithm string `json:"alg"`

	// Represents the token type.
	Typ string `json:"typ"`
}

func (h *Header) encode() (string, error) {
	b, err := json.Marshal(h)
	if err != nil {
		return "", err
	}
	return base64Encode(b), nil
}

// Decode decodes a claim set from a JWS payload.
func Decode(payload string) (*ClaimSet, error) {
	// decode returned id token to get expiry
	s := strings.Split(payload, ".")
	if len(s) < 2 {
		// TODO(jbd): Provide more context about the error.
		return nil, errors.New("jws: invalid token received")
	}
	decoded, err := base64Decode(s[1])
	if err != nil {
		return nil, err
	}
	c := &ClaimSet{}
	err = json.NewDecoder(bytes.NewBuffer(decoded)).Decode(c)
	return c, err
}

// Signer returns a signature for the given data.
type Signer func(data []byte) (sig []byte, err error)

// EncodeWithSigner encodes a header and claim set with the provided signer.
func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
	head, err := header.encode()
	if err != nil {
		return "", err
	}
	cs, err := c.encode()
	if err != nil {
		return "", err
	}
	ss := fmt.Sprintf("%s.%s", head, cs)
	sig, err := sg([]byte(ss))
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil
}

// Encode encodes a signed JWS with provided header and claim set.
// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
	sg := func(data []byte) (sig []byte, err error) {
		h := sha256.New()
		h.Write([]byte(data))
		return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
	}
	return EncodeWithSigner(header, c, sg)
}

// base64Encode returns and Base64url encoded version of the input string with any
// trailing "=" stripped.
func base64Encode(b []byte) string {
	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

// base64Decode decodes the Base64url encoded string
func base64Decode(s string) ([]byte, error) {
	// add back missing padding
	switch len(s) % 4 {
	case 2:
		s += "=="
	case 3:
		s += "="
	}
	return base64.URLEncoding.DecodeString(s)
}
<|endoftext|>


<commit_before>package jsonext

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"
)

type CatchAll map[string]interface{}

var catchAllType = reflect.TypeOf(CatchAll{})

func Unmarshal(data []byte, v interface{}) error {
	return NewDecoder(bytes.NewReader(data)).Decode(v)
}

type Decoder struct {
	*json.Decoder
}

func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{json.NewDecoder(r)}
}

func (d *Decoder) Decode(v interface{}) error {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return &json.InvalidUnmarshalError{reflect.TypeOf(v)}
	}

	if rv.Elem().Kind() == reflect.Struct {
		return d.decodeStruct(rv)
	}

	return d.Decoder.Decode(v)
}

func (d *Decoder) decodeStruct(rv reflect.Value) error {
	var data map[string]interface{}
	err := d.Decoder.Decode(&data)
	if err != nil {
		return err
	}
	return d.descendStruct(rv.Elem(), data)
}

func (d *Decoder) descendStruct(rv reflect.Value, data map[string]interface{}) error {
	if data == nil {
		return nil
	}
	t := rv.Type()

	var rca reflect.Value
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		fieldv := rv.Field(i)
		jsonFieldname := fieldnameFromTag(field.Tag.Get("json"))
		tag := field.Tag.Get("jsonext")
		switch tag {
		case "descend":
			if field.Type.Kind() != reflect.Struct {
				return fmt.Errorf("Cannot descend into field %s, because it is not a struct", field.Name)
			}
			if jsonFieldname == "" || jsonFieldname == "-" {
				break
			}
			subData := data[jsonFieldname]
			if subData == nil {
				break
			}
			err := d.descendStruct(fieldv, subData.(map[string]interface{}))
			if err != nil {
				return err
			}
			delete(data, jsonFieldname)
		case "catchall":
			if field.Type != catchAllType {
				return fmt.Errorf("Field %s has tag catchall but does not have type CatchAll", field.Name)
			}
			rca = fieldv
		case "":
			err := remarshal(fieldv.Addr().Interface(), data[jsonFieldname])
			if err != nil {
				return fmt.Errorf("Value for %s did not marshal into Go type %s: %s", jsonFieldname, field.Type, err)
			}
			delete(data, jsonFieldname)
		default:
			return fmt.Errorf("Unknown tag %s on field %s", tag, field.Name)
		}
	}

	// Data now contains only the fields which could not be
	// mapped onto struct fields.
	rca.Set(reflect.ValueOf(data))

	return nil
}

func fieldnameFromTag(jsontag string) string {
	return strings.Split(jsontag, ",")[0]
}

func remarshal(dst interface{}, src interface{}) error {
	data, err := json.Marshal(src)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, dst)
}
<commit_msg>Handle fields with no json tag correctly<commit_after>package jsonext

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"reflect"
	"strings"
)

type CatchAll map[string]interface{}

var catchAllType = reflect.TypeOf(CatchAll{})

func Unmarshal(data []byte, v interface{}) error {
	return NewDecoder(bytes.NewReader(data)).Decode(v)
}

type Decoder struct {
	*json.Decoder
}

func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{json.NewDecoder(r)}
}

func (d *Decoder) Decode(v interface{}) error {
	rv := reflect.ValueOf(v)
	if rv.Kind() != reflect.Ptr || rv.IsNil() {
		return &json.InvalidUnmarshalError{reflect.TypeOf(v)}
	}

	if rv.Elem().Kind() == reflect.Struct {
		return d.decodeStruct(rv)
	}

	return d.Decoder.Decode(v)
}

func (d *Decoder) decodeStruct(rv reflect.Value) error {
	var data map[string]interface{}
	err := d.Decoder.Decode(&data)
	if err != nil {
		return err
	}
	return d.descendStruct(rv.Elem(), data)
}

func (d *Decoder) descendStruct(rv reflect.Value, data map[string]interface{}) error {
	if data == nil {
		return nil
	}
	t := rv.Type()

	var rca reflect.Value
	for i := 0; i < t.NumField(); i++ {
		field := t.Field(i)
		fieldv := rv.Field(i)
		jsonFieldname := jsonFieldname(field)
		tag := field.Tag.Get("jsonext")
		switch tag {
		case "descend":
			if field.Type.Kind() != reflect.Struct {
				return fmt.Errorf("Cannot descend into field %s, because it is not a struct", field.Name)
			}
			if jsonFieldname == "" || jsonFieldname == "-" {
				break
			}
			subData := data[jsonFieldname]
			if subData == nil {
				break
			}
			err := d.descendStruct(fieldv, subData.(map[string]interface{}))
			if err != nil {
				return err
			}
			delete(data, jsonFieldname)
		case "catchall":
			if field.Type != catchAllType {
				return fmt.Errorf("Field %s has tag catchall but does not have type CatchAll", field.Name)
			}
			rca = fieldv
		case "":
			err := remarshal(fieldv.Addr().Interface(), data[jsonFieldname])
			if err != nil {
				return fmt.Errorf("Value for %s did not marshal into Go type %s: %s", jsonFieldname, field.Type, err)
			}
			delete(data, jsonFieldname)
		default:
			return fmt.Errorf("Unknown tag %s on field %s", tag, field.Name)
		}
	}

	// Data now contains only the fields which could not be
	// mapped onto struct fields.
	rca.Set(reflect.ValueOf(data))

	return nil
}

func jsonFieldname(f reflect.StructField) string {
	jsonTag := strings.Split(f.Tag.Get("json"), ",")[0]
	if jsonTag == "" {
		return f.Name
	}
	return jsonTag
}

func remarshal(dst interface{}, src interface{}) error {
	data, err := json.Marshal(src)
	if err != nil {
		return err
	}
	return json.Unmarshal(data, dst)
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package instrument

import (
	"errors"
	"log"
	"runtime"
	"sync"
	"time"
)

var (
	// Revision is the VCS revision associated with this build. Overridden using ldflags
	// at compile time. Example:
	// $ go build -ldflags "-X github.com/m3db/m3x/instrument.Revision=abcdef" ...
	// Adapted from: https://www.atatus.com/blog/golang-auto-build-versioning/
	Revision = "unknown"

	// Branch is the VCS branch associated with this build.
	Branch = "unknown"

	// BuildDate is the date this build was created.
	BuildDate = "unknown"

	// LogBuildInfoAtStartup controls whether we log build information at startup.
	LogBuildInfoAtStartup = false

	// goVersion is the current runtime version.
	goVersion = runtime.Version()

	// metricName is the emitted metric's name.
	metricName = "build-information"
)

var (
	errAlreadyStarted = errors.New("reporter already started")
	errNotStarted     = errors.New("reporter not started")
)

// LogBuildInformation logs the build information to the provided logger.
func LogBuildInformation() {
	log.Printf("Go Runtime version: %s\n", goVersion)
	log.Printf("Build Revision:     %s\n", Revision)
	log.Printf("Build Branch:       %s\n", Branch)
	log.Printf("Build Date:         %s\n", BuildDate)
}

func init() {
	if LogBuildInfoAtStartup {
		LogBuildInformation()
	}
}

type buildReporter struct {
	sync.Mutex

	opts    Options
	active  bool
	closeCh chan struct{}
	doneCh  chan struct{}
}

// NewBuildReporter returns a new build version reporter.
func NewBuildReporter(
	opts Options,
) BuildReporter {
	return &buildReporter{
		opts: opts,
	}
}

func (b *buildReporter) Start() error {
	b.Lock()
	defer b.Unlock()
	if b.active {
		return errAlreadyStarted
	}
	b.active = true
	b.closeCh = make(chan struct{})
	b.doneCh = make(chan struct{})
	go b.report()
	return nil
}

func (b *buildReporter) report() {
	scope := b.opts.MetricsScope().Tagged(map[string]string{
		"revision":   Revision,
		"branch":     Branch,
		"build-date": BuildDate,
		"go-version": goVersion,
	})
	gauge := scope.Gauge(metricName)
	gauge.Update(1.0)

	ticker := time.NewTicker(b.opts.ReportInterval())
	defer func() {
		close(b.doneCh)
		ticker.Stop()
	}()

	for {
		select {
		case <-ticker.C:
			gauge.Update(1.0)
		case <-b.closeCh:
			return
		}
	}
}

func (b *buildReporter) Close() error {
	b.Lock()
	defer b.Unlock()
	if !b.active {
		return errNotStarted
	}
	close(b.closeCh)
	<-b.doneCh
	b.active = false
	return nil
}
<commit_msg>Fix LogBuildInfoAtStartup (#90)<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package instrument

import (
	"errors"
	"log"
	"runtime"
	"sync"
	"time"
)

var (
	// Revision is the VCS revision associated with this build. Overridden using ldflags
	// at compile time. Example:
	// $ go build -ldflags "-X github.com/m3db/m3x/instrument.Revision=abcdef" ...
	// Adapted from: https://www.atatus.com/blog/golang-auto-build-versioning/
	Revision = "unknown"

	// Branch is the VCS branch associated with this build.
	Branch = "unknown"

	// BuildDate is the date this build was created.
	BuildDate = "unknown"

	// LogBuildInfoAtStartup controls whether we log build information at startup. If its
	// set to a non-empty string, we log the build information at process startup.
	LogBuildInfoAtStartup string

	// goVersion is the current runtime version.
	goVersion = runtime.Version()

	// metricName is the emitted metric's name.
	metricName = "build-information"
)

var (
	errAlreadyStarted = errors.New("reporter already started")
	errNotStarted     = errors.New("reporter not started")
)

// LogBuildInfo logs the build information to the provided logger.
func LogBuildInfo() {
	log.Printf("Go Runtime version: %s\n", goVersion)
	log.Printf("Build Revision:     %s\n", Revision)
	log.Printf("Build Branch:       %s\n", Branch)
	log.Printf("Build Date:         %s\n", BuildDate)
}

func init() {
	if LogBuildInfoAtStartup != "" {
		LogBuildInfo()
	}
}

type buildReporter struct {
	sync.Mutex

	opts    Options
	active  bool
	closeCh chan struct{}
	doneCh  chan struct{}
}

// NewBuildReporter returns a new build version reporter.
func NewBuildReporter(
	opts Options,
) BuildReporter {
	return &buildReporter{
		opts: opts,
	}
}

func (b *buildReporter) Start() error {
	b.Lock()
	defer b.Unlock()
	if b.active {
		return errAlreadyStarted
	}
	b.active = true
	b.closeCh = make(chan struct{})
	b.doneCh = make(chan struct{})
	go b.report()
	return nil
}

func (b *buildReporter) report() {
	scope := b.opts.MetricsScope().Tagged(map[string]string{
		"revision":   Revision,
		"branch":     Branch,
		"build-date": BuildDate,
		"go-version": goVersion,
	})
	gauge := scope.Gauge(metricName)
	gauge.Update(1.0)

	ticker := time.NewTicker(b.opts.ReportInterval())
	defer func() {
		close(b.doneCh)
		ticker.Stop()
	}()

	for {
		select {
		case <-ticker.C:
			gauge.Update(1.0)
		case <-b.closeCh:
			return
		}
	}
}

func (b *buildReporter) Close() error {
	b.Lock()
	defer b.Unlock()
	if !b.active {
		return errNotStarted
	}
	close(b.closeCh)
	<-b.doneCh
	b.active = false
	return nil
}
<|endoftext|>


<commit_before>package util

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/assertions"
)

func newTokenServer(a *Assertion) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		a.So(r.RequestURI, ShouldEqual, "/token")
		a.So(r.Method, ShouldEqual, "POST")

		username, password, ok := r.BasicAuth()
		a.So(ok, ShouldBeTrue)
		a.So(username, ShouldEqual, "ttnctl")
		a.So(password, ShouldEqual, "")

		grantType := r.FormValue("grant_type")
		if grantType == "password" {
			handleNewToken(a, w, r)
		} else if grantType == "refresh_token" {
			handleRefreshToken(a, w, r)
		} else {
			w.WriteHeader(http.StatusNotFound)
		}
	}))
}

func handleNewToken(a *Assertion, w http.ResponseWriter, r *http.Request) {
	var resp token
	if r.FormValue("username") == "jantje@test.org" && r.FormValue("password") == "secret" {
		resp = token{
			AccessToken:  "123",
			RefreshToken: "ABC",
			ExpiresIn:    3600,
		}
		w.WriteHeader(http.StatusOK)
	} else {
		resp = token{
			Error:            "invalid_credentials",
			ErrorDescription: "Invalid credentials",
		}
		w.WriteHeader(http.StatusForbidden)
	}

	encoder := json.NewEncoder(w)
	err := encoder.Encode(&resp)
	a.So(err, ShouldBeNil)
}

func handleRefreshToken(a *Assertion, w http.ResponseWriter, r *http.Request) {
	var resp token
	if r.FormValue("refresh_token") == "ABC" {
		resp = token{
			AccessToken:  "456",
			RefreshToken: "DEF",
			ExpiresIn:    3600,
		}
		w.WriteHeader(http.StatusOK)
	} else {
		resp = token{
			Error:            "invalid_grant",
			ErrorDescription: "Refresh token not found",
		}
		w.WriteHeader(http.StatusBadRequest)
	}

	encoder := json.NewEncoder(w)
	err := encoder.Encode(&resp)
	a.So(err, ShouldBeNil)
}

func TestLogin(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	_, err := Login(server.URL, "pietje@test.org", "secret")
	a.So(err, ShouldNotBeNil)
	a.So(err.Error(), ShouldEqual, "Invalid credentials")

	loginAuth, err := Login(server.URL, "jantje@test.org", "secret")
	a.So(err, ShouldBeNil)
	a.So(loginAuth, ShouldNotBeNil)
	a.So(loginAuth.AccessToken, ShouldEqual, "123")
	a.So(loginAuth.RefreshToken, ShouldEqual, "ABC")
	a.So(loginAuth.Email, ShouldEqual, "jantje@test.org")

	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldNotBeNil)
	a.So(loginAuth, ShouldResemble, loadedAuth)

	// Check if we get this token on the HTTP request
	req, err := NewRequestWithAuth(server.URL, "GET", "http://external", nil)
	a.So(err, ShouldBeNil)
	a.So(req, ShouldNotBeNil)
	a.So(req.Header.Get("Authorization"), ShouldEqual, fmt.Sprintf("bearer %s", loadedAuth.AccessToken))

	Logout(server.URL)
}

func TestLogout(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldBeNil)

	// Login
	loginAuth, err := Login(server.URL, "jantje@test.org", "secret")
	a.So(err, ShouldBeNil)
	a.So(loginAuth, ShouldNotBeNil)

	// Logout
	err = Logout(server.URL)
	a.So(err, ShouldBeNil)
	loadedAuth, err = LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldBeNil)

	// Make sure that we can't make an HTTP request
	_, err = NewRequestWithAuth(server.URL, "GET", "http://external", nil)
	a.So(err, ShouldNotBeNil)
}

func TestLoadWithRefresh(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)

	// Save an expired token
	expires := time.Now().Add(time.Duration(-1) * time.Hour)
	savedAuth, err := saveAuth(server.URL, "jantje@test.org", "123", "ABC", expires)
	a.So(err, ShouldBeNil)

	// Refresh the token
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldNotBeNil)
	a.So(savedAuth, ShouldNotResemble, loadedAuth)
	a.So(loadedAuth.AccessToken, ShouldEqual, "456")
	a.So(loadedAuth.RefreshToken, ShouldEqual, "DEF")
	a.So(loadedAuth.Email, ShouldEqual, "jantje@test.org")

	Logout(server.URL)
}

func TestLoadWithInvalidRefresh(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)

	// Save an expired token
	expires := time.Now().Add(time.Duration(-1) * time.Hour)
	_, err = saveAuth(server.URL, "pietje@test.org", "987", "ZYX", expires)
	a.So(err, ShouldBeNil)

	// Refresh the token
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldNotBeNil)
	a.So(err.Error(), ShouldEqual, "Refresh token not found")
	a.So(loadedAuth, ShouldBeNil)

	Logout(server.URL)
}
<commit_msg>Fixed test<commit_after>package util

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	. "github.com/smartystreets/assertions"
)

func newTokenServer(a *Assertion) *httptest.Server {
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		a.So(r.RequestURI, ShouldEqual, "/users/token")
		a.So(r.Method, ShouldEqual, "POST")

		username, password, ok := r.BasicAuth()
		a.So(ok, ShouldBeTrue)
		a.So(username, ShouldEqual, "ttnctl")
		a.So(password, ShouldEqual, "")

		grantType := r.FormValue("grant_type")
		if grantType == "password" {
			handleNewToken(a, w, r)
		} else if grantType == "refresh_token" {
			handleRefreshToken(a, w, r)
		} else {
			w.WriteHeader(http.StatusNotFound)
		}
	}))
}

func handleNewToken(a *Assertion, w http.ResponseWriter, r *http.Request) {
	var resp token
	if r.FormValue("username") == "jantje@test.org" && r.FormValue("password") == "secret" {
		resp = token{
			AccessToken:  "123",
			RefreshToken: "ABC",
			ExpiresIn:    3600,
		}
		w.WriteHeader(http.StatusOK)
	} else {
		resp = token{
			Error:            "invalid_credentials",
			ErrorDescription: "Invalid credentials",
		}
		w.WriteHeader(http.StatusForbidden)
	}

	encoder := json.NewEncoder(w)
	err := encoder.Encode(&resp)
	a.So(err, ShouldBeNil)
}

func handleRefreshToken(a *Assertion, w http.ResponseWriter, r *http.Request) {
	var resp token
	if r.FormValue("refresh_token") == "ABC" {
		resp = token{
			AccessToken:  "456",
			RefreshToken: "DEF",
			ExpiresIn:    3600,
		}
		w.WriteHeader(http.StatusOK)
	} else {
		resp = token{
			Error:            "invalid_grant",
			ErrorDescription: "Refresh token not found",
		}
		w.WriteHeader(http.StatusBadRequest)
	}

	encoder := json.NewEncoder(w)
	err := encoder.Encode(&resp)
	a.So(err, ShouldBeNil)
}

func TestLogin(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	_, err := Login(server.URL, "pietje@test.org", "secret")
	a.So(err, ShouldNotBeNil)
	a.So(err.Error(), ShouldEqual, "Invalid credentials")

	loginAuth, err := Login(server.URL, "jantje@test.org", "secret")
	a.So(err, ShouldBeNil)
	a.So(loginAuth, ShouldNotBeNil)
	a.So(loginAuth.AccessToken, ShouldEqual, "123")
	a.So(loginAuth.RefreshToken, ShouldEqual, "ABC")
	a.So(loginAuth.Email, ShouldEqual, "jantje@test.org")

	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldNotBeNil)
	a.So(loginAuth, ShouldResemble, loadedAuth)

	// Check if we get this token on the HTTP request
	req, err := NewRequestWithAuth(server.URL, "GET", "http://external", nil)
	a.So(err, ShouldBeNil)
	a.So(req, ShouldNotBeNil)
	a.So(req.Header.Get("Authorization"), ShouldEqual, fmt.Sprintf("bearer %s", loadedAuth.AccessToken))

	Logout(server.URL)
}

func TestLogout(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldBeNil)

	// Login
	loginAuth, err := Login(server.URL, "jantje@test.org", "secret")
	a.So(err, ShouldBeNil)
	a.So(loginAuth, ShouldNotBeNil)

	// Logout
	err = Logout(server.URL)
	a.So(err, ShouldBeNil)
	loadedAuth, err = LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldBeNil)

	// Make sure that we can't make an HTTP request
	_, err = NewRequestWithAuth(server.URL, "GET", "http://external", nil)
	a.So(err, ShouldNotBeNil)
}

func TestLoadWithRefresh(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)

	// Save an expired token
	expires := time.Now().Add(time.Duration(-1) * time.Hour)
	savedAuth, err := saveAuth(server.URL, "jantje@test.org", "123", "ABC", expires)
	a.So(err, ShouldBeNil)

	// Refresh the token
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldBeNil)
	a.So(loadedAuth, ShouldNotBeNil)
	a.So(savedAuth, ShouldNotResemble, loadedAuth)
	a.So(loadedAuth.AccessToken, ShouldEqual, "456")
	a.So(loadedAuth.RefreshToken, ShouldEqual, "DEF")
	a.So(loadedAuth.Email, ShouldEqual, "jantje@test.org")

	Logout(server.URL)
}

func TestLoadWithInvalidRefresh(t *testing.T) {
	a := New(t)
	server := newTokenServer(a)
	defer server.Close()

	// Make sure we're not logged on
	err := Logout(server.URL)
	a.So(err, ShouldBeNil)

	// Save an expired token
	expires := time.Now().Add(time.Duration(-1) * time.Hour)
	_, err = saveAuth(server.URL, "pietje@test.org", "987", "ZYX", expires)
	a.So(err, ShouldBeNil)

	// Refresh the token
	loadedAuth, err := LoadAuth(server.URL)
	a.So(err, ShouldNotBeNil)
	a.So(err.Error(), ShouldEqual, "Refresh token not found")
	a.So(loadedAuth, ShouldBeNil)

	Logout(server.URL)
}
<|endoftext|>


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

//go:build ignore
// +build ignore

package main

import (
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

func pngDir() (string, error) {
	dir, err := exec.Command("go", "list", "-f", "{{.Dir}}", "image/png").Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(dir)), nil
}

func pngFiles() ([]string, error) {
	files, err := exec.Command("go", "list", "-f", `{{join .GoFiles ","}}`, "image/png").Output()
	if err != nil {
		return nil, err
	}
	return strings.Split(strings.TrimSpace(string(files)), ","), nil
}

func run() error {
	dir, err := pngDir()
	if err != nil {
		return err
	}

	files, err := pngFiles()
	if err != nil {
		return err
	}

	for _, f := range files {
		in, err := os.Open(filepath.Join(dir, f))
		if err != nil {
			return err
		}
		defer in.Close()

		out, err := os.Create("stdlib" + f)
		if err != nil {
			return err
		}
		defer out.Close()

		// TODO: Remove call of RegisterDecoder

		data, err := ioutil.ReadAll(in)
		if err != nil {
			return err
		}
		fset := token.NewFileSet()
		tree, err := parser.ParseFile(fset, "", string(data), parser.ParseComments)
		if err != nil {
			return err
		}

		astutil.Apply(tree, func(c *astutil.Cursor) bool {
			stmt, ok := c.Node().(*ast.ExprStmt)
			if !ok {
				return true
			}
			call, ok := stmt.X.(*ast.CallExpr)
			if !ok {
				return true
			}
			s, ok := call.Fun.(*ast.SelectorExpr)
			if !ok {
				return true
			}
			receiver, ok := s.X.(*ast.Ident)
			if !ok {
				return true
			}
			// Delete registering PNG format.
			if receiver.Name == "image" && s.Sel.Name == "RegisterFormat" {
				c.Delete()
			}
			return true
		}, nil)

		fmt.Fprintln(out, "// Code generated by gen.go. DO NOT EDIT.")
		fmt.Fprintln(out)
		format.Node(out, fset, tree)
	}
	return nil
}

func main() {
	if err := run(); err != nil {
		panic(err)
	}
}
<commit_msg>internal/png: clean up files before generating<commit_after>// Copyright 2018 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build ignore
// +build ignore

package main

import (
	"fmt"
	"go/ast"
	"go/format"
	"go/parser"
	"go/token"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"golang.org/x/tools/go/ast/astutil"
)

func pngDir() (string, error) {
	dir, err := exec.Command("go", "list", "-f", "{{.Dir}}", "image/png").Output()
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(dir)), nil
}

func pngFiles() ([]string, error) {
	files, err := exec.Command("go", "list", "-f", `{{join .GoFiles ","}}`, "image/png").Output()
	if err != nil {
		return nil, err
	}
	return strings.Split(strings.TrimSpace(string(files)), ","), nil
}

func run() error {
	dir, err := pngDir()
	if err != nil {
		return err
	}

	files, err := pngFiles()
	if err != nil {
		return err
	}

	const prefix = "stdlib"

	matches, err := filepath.Glob(prefix + "*.go")
	if err != nil {
		return err
	}
	for _, f := range matches {
		if err := os.Remove(f); err != nil {
			return err
		}
	}

	for _, f := range files {
		in, err := os.Open(filepath.Join(dir, f))
		if err != nil {
			return err
		}
		defer in.Close()

		out, err := os.Create(prefix + f)
		if err != nil {
			return err
		}
		defer out.Close()

		// TODO: Remove call of RegisterDecoder

		data, err := ioutil.ReadAll(in)
		if err != nil {
			return err
		}
		fset := token.NewFileSet()
		tree, err := parser.ParseFile(fset, "", string(data), parser.ParseComments)
		if err != nil {
			return err
		}

		astutil.Apply(tree, func(c *astutil.Cursor) bool {
			stmt, ok := c.Node().(*ast.ExprStmt)
			if !ok {
				return true
			}
			call, ok := stmt.X.(*ast.CallExpr)
			if !ok {
				return true
			}
			s, ok := call.Fun.(*ast.SelectorExpr)
			if !ok {
				return true
			}
			receiver, ok := s.X.(*ast.Ident)
			if !ok {
				return true
			}
			// Delete registering PNG format.
			if receiver.Name == "image" && s.Sel.Name == "RegisterFormat" {
				c.Delete()
			}
			return true
		}, nil)

		fmt.Fprintln(out, "// Code generated by gen.go. DO NOT EDIT.")
		fmt.Fprintln(out)
		format.Node(out, fset, tree)
	}
	return nil
}

func main() {
	if err := run(); err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package internal

import (
	"fmt"
	"strings"
)

// the final version string
var version string

// -ldflags "-X github.com/matrix-org/dendrite/internal.branch=master"
var branch string

// -ldflags "-X github.com/matrix-org/dendrite/internal.build=alpha"
var build string

const (
	VersionMajor = 0
	VersionMinor = 4
	VersionPatch = 1
	VersionTag   = "" // example: "rc1"
)

func VersionString() string {
	return version
}

func init() {
	version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
	if VersionTag != "" {
		version += "-" + VersionTag
	}
	parts := []string{}
	if build != "" {
		parts = append(parts, build)
	}
	if branch != "" {
		parts = append(parts, branch)
	}
	if len(parts) > 0 {
		version += "+" + strings.Join(parts, ".")
	}
}
<commit_msg>Version 0.5.0rc1<commit_after>package internal

import (
	"fmt"
	"strings"
)

// the final version string
var version string

// -ldflags "-X github.com/matrix-org/dendrite/internal.branch=master"
var branch string

// -ldflags "-X github.com/matrix-org/dendrite/internal.build=alpha"
var build string

const (
	VersionMajor = 0
	VersionMinor = 5
	VersionPatch = 0
	VersionTag   = "rc1" // example: "rc1"
)

func VersionString() string {
	return version
}

func init() {
	version = fmt.Sprintf("%d.%d.%d", VersionMajor, VersionMinor, VersionPatch)
	if VersionTag != "" {
		version += "-" + VersionTag
	}
	parts := []string{}
	if build != "" {
		parts = append(parts, build)
	}
	if branch != "" {
		parts = append(parts, branch)
	}
	if len(parts) > 0 {
		version += "+" + strings.Join(parts, ".")
	}
}
<|endoftext|>