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

package main

import (
	"bytes"
	"io/ioutil"
	"strconv"

	_ "github.com/go-sql-driver/mysql"
	"gopkg.in/goyy/goyy.v0/comm/log"
	"gopkg.in/goyy/goyy.v0/data/xsql"
	"gopkg.in/goyy/goyy.v0/util/files"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/util/times"
	"gopkg.in/goyy/goyy.v0/util/uuids"
)

func genMenu() {
	xsql.SetPriority(log.Perror)
	// generate the header.html
	for _, p := range conf.projects {
		clidir := "../" + strings.AfterLast(p.Admpath(), "/")
		dir := clidir + "/templates/layout/include/"
		dstfile := dir + "header.html"
		if !files.IsExist(dstfile) {
			files.MkdirAll(dir, 0755)
		}
		data := map[string]interface{}{
			"Project": p,
			"Modules": conf.modules,
			"Tables":  conf.tables,
		}
		buf := bytes.Buffer{}
		tmpl := newTmpl(tmplMenu)
		tmpl.Execute(&buf, data)
		ioutil.WriteFile(dstfile, buf.Bytes(), 0755)
	}
	// insert into sys_menu
	for _, p := range conf.projects {
		insertRootMenu(p.database.driverName, p.ID())
		for mi, m := range conf.modules {
			if p.ID() == m.project.ID() && m.Menu() == "true" {
				root := &menu{
					id:      "root",
					code:    "00",
					name:    i18N.Message("tmpl.menu.data.root"),
					ordinal: "00",
				}
				po := strings.PadLeft(strconv.Itoa(mi+1), 2, "0")
				pp := addMenu(p.database.driverName, p.ID(), m.ID(), "", m.Name(), po, "10", root) // module
				for ti, t := range conf.tables {
					if m.ID() == t.module.ID() && t.Menu() == "true" && t.ID() != "-" {
						to := strings.PadLeft(strconv.Itoa(ti+1), 2, "0")
						mp := addMenu(p.database.driverName, p.ID(), m.ID(), t.ID(), t.Name(), to, "20", pp) // table
						buttons := strings.Split(t.Buttons(), ",")
						for i, button := range buttons {
							if strings.IsBlank(button) {
								continue
							}
							addMenu(p.database.driverName, p.ID(), m.ID(), t.ID(), button, strconv.Itoa((i+2)*5), "30", mp)
						}
					}
				}
			}
		}
	}
}

func insertRootMenu(driverName, pid string) {
	db := getDB(driverName, pid)
	csql := "SELECT count(1) FROM sys_menu WHERE id = ?"

	sql := `INSERT INTO sys_menu
	(id, href, target, icon, hidden, permission, code, name, fullname, genre, ordinal, parent_id, parent_ids, parent_codes, parent_names, leaf, grade, memo, creates, creater, created, modifier, modified, version, deletion, artifical, history)
	VALUES
	('root', null, null, null, 0, null, '00', ?, null, '00', '00', null, null, null, null, 0, 1, null, null, null, ?, null, ?, 0, 0, 0, 0);`

	count, err := db.Query(csql, "root").Int()
	if err != nil {
		logger.Error(err)
		return
	}
	if count == 0 {
		name := i18N.Message("tmpl.menu.data.root")
		now := times.NowUnix()
		_, err = db.Exec(sql, name, now, now)
		if err != nil {
			logger.Error(err)
			return
		}
	}
}

func addMenu(driverName, pid, mid, tid, xname, ordinal, genre string, parent *menu) *menu {
	db := getDB(driverName, pid)
	id := uuids.New()
	now := times.NowUnix()
	m := &menu{
		id:       id,
		hidden:   "0",
		code:     parent.ordinal + ordinal,
		name:     xname,
		parentID: parent.id,
		leaf:     "0",
		genre:    genre,
		ordinal:  parent.ordinal + ordinal,
	}
	if parent.id == "root" {
		m.parentIDs = parent.id
		m.parentCodes = parent.code
	} else {
		m.parentIDs = parent.parentIDs + "," + parent.id
		m.parentCodes = parent.parentCodes + "," + parent.code
	}
	switch genre {
	case "10":
		if parent.id == "root" {
			m.fullname = xname
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + xname
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.grade = "2"
	case "20":
		m.href = "/" + mid + "/" + tid
		m.name = xname + i18N.Message("tmpl.menu.manage")
		if parent.id == "root" {
			m.fullname = m.name
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + m.name
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.grade = "3"
	case "30":
		var name string
		xconf := util.DecodeXML(xbuttons)
		for _, v := range xconf.Buttons.Button {
			if v.ID == xname {
				name = v.Name
			}
		}
		m.hidden = "1"
		m.permission = mid + ":" + tid + ":" + xname
		m.name = name
		if parent.id == "root" {
			m.fullname = m.name
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + m.name
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.leaf = "1"
		m.grade = "4"
	}

	csql := "SELECT count(1) FROM sys_menu WHERE code = ?"

	sql := `INSERT INTO sys_menu
	(id, href, target, icon, hidden, permission, code, name, fullname, genre, ordinal, parent_id, parent_ids, parent_codes, parent_names, leaf, grade, memo, creates, creater, created, modifier, modified, version, deletion, artifical, history)
	VALUES
	(?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL, ?, NULL, ?, 0, 0, 0, 0)`

	count, err := db.Query(csql, m.code).Int()
	if err != nil {
		logger.Error(err)
		return m
	}
	if count == 0 {
		_, err = db.Exec(sql, m.id, m.href, m.hidden, m.permission, m.code, m.name, m.fullname, m.genre, m.ordinal, m.parentID, m.parentIDs, m.parentCodes, m.parentNames, m.leaf, m.grade, now, now)
		if err != nil {
			logger.Error(err)
			return m
		}
	}
	return m
}

type menu struct {
	id, href, hidden, permission, code, name, fullname, genre, ordinal, parentID, parentIDs, parentCodes, parentNames, leaf, grade string
}
<commit_msg>Add support to new project on xgen<commit_after>// Copyright 2014 The goyy Authors.  All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"io/ioutil"
	"strconv"

	_ "github.com/go-sql-driver/mysql"
	"gopkg.in/goyy/goyy.v0/comm/log"
	"gopkg.in/goyy/goyy.v0/data/xsql"
	"gopkg.in/goyy/goyy.v0/util/files"
	"gopkg.in/goyy/goyy.v0/util/strings"
	"gopkg.in/goyy/goyy.v0/util/times"
	"gopkg.in/goyy/goyy.v0/util/uuids"
)

func genMenu() {
	xsql.SetPriority(log.Perror)
	// generate the header.html
	for _, p := range conf.projects {
		clidir := "../" + strings.AfterLast(p.Admpath(), "/")
		dir := clidir + "/templates/layout/include/"
		dstfile := dir + "header.html"
		if !files.IsExist(dstfile) {
			files.MkdirAll(dir, 0755)
		}
		data := map[string]interface{}{
			"Project": p,
			"Modules": conf.modules,
			"Tables":  conf.tables,
		}
		buf := bytes.Buffer{}
		tmpl := newTmpl(tmplMenu)
		tmpl.Execute(&buf, data)
		ioutil.WriteFile(dstfile, buf.Bytes(), 0755)
	}
	// insert into sys_menu
	for _, p := range conf.projects {
		insertRootMenu(p.database.driverName, p.ID())
		for mi, m := range conf.modules {
			if p.ID() == m.project.ID() && m.Menu() == "true" {
				root := &menu{
					id:      "root",
					code:    "00",
					name:    i18N.Message("tmpl.menu.data.root"),
					ordinal: "00",
				}
				po := strings.PadLeft(strconv.Itoa(mi+1), 2, "0")
				pp := addMenu(p.database.driverName, p.ID(), m.ID(), "", m.Name(), po, "10", root) // module
				for ti, t := range conf.tables {
					if m.ID() == t.module.ID() && t.Menu() == "true" && t.ID() != "-" {
						to := strings.PadLeft(strconv.Itoa(ti+1), 2, "0")
						mp := addMenu(p.database.driverName, p.ID(), m.ID(), t.ID(), t.Name(), to, "20", pp) // table
						buttons := strings.Split(t.Buttons(), ",")
						for i, button := range buttons {
							if strings.IsBlank(button) {
								continue
							}
							addMenu(p.database.driverName, p.ID(), m.ID(), t.ID(), button, strconv.Itoa((i+2)*5), "30", mp)
						}
					}
				}
			}
		}
	}
}

func insertRootMenu(driverName, pid string) {
	db := getDB(driverName, pid)
	csql := "SELECT count(1) FROM sys_menu WHERE id = ?"

	sql := `INSERT INTO sys_menu
	(id, href, target, icon, hidden, permission, code, name, fullname, genre, ordinal, parent_id, parent_ids, parent_codes, parent_names, leaf, grade, memo, creates, creater, created, modifier, modified, version, deletion, artifical, history)
	VALUES
	('root', null, null, null, 0, null, '00', ?, null, '00', '00', null, null, null, null, 0, 1, null, null, null, ?, null, ?, 0, 0, 0, 0);`

	count, err := db.Query(csql, "root").Int()
	if err != nil {
		logger.Error(err)
		return
	}
	if count == 0 {
		name := i18N.Message("tmpl.menu.data.root")
		now := times.NowUnix()
		_, err = db.Exec(sql, name, now, now)
		if err != nil {
			logger.Error(err)
			return
		}
	}
}

func addMenu(driverName, pid, mid, tid, xname, ordinal, genre string, parent *menu) *menu {
	db := getDB(driverName, pid)
	id := uuids.New()
	now := times.NowUnix()
	m := &menu{
		id:       id,
		hidden:   "0",
		code:     parent.ordinal + ordinal,
		name:     xname,
		parentID: parent.id,
		leaf:     "0",
		genre:    genre,
		ordinal:  parent.ordinal + ordinal,
	}
	if parent.id == "root" {
		m.parentIDs = parent.id
		m.parentCodes = parent.code
	} else {
		m.parentIDs = parent.parentIDs + "," + parent.id
		m.parentCodes = parent.parentCodes + "," + parent.code
	}
	switch genre {
	case "10":
		if parent.id == "root" {
			m.fullname = xname
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + xname
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.grade = "2"
	case "20":
		m.href = "/" + mid + "/" + tid
		m.name = xname + i18N.Message("tmpl.menu.manage")
		if parent.id == "root" {
			m.fullname = m.name
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + m.name
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.grade = "3"
	case "30":
		var name string
		xconf := util.DecodeXML(xbuttons)
		for _, v := range xconf.Buttons.Button {
			if v.ID == xname {
				name = v.Name
			}
		}
		m.hidden = "1"
		m.permission = mid + ":" + tid + ":" + xname
		m.name = name
		if parent.id == "root" {
			m.fullname = m.name
			m.parentNames = parent.name
		} else {
			m.fullname = parent.fullname + " - " + m.name
			m.parentNames = parent.parentNames + "," + parent.name
		}
		m.leaf = "1"
		m.grade = "4"
	}

	csql := "SELECT count(1) FROM sys_menu WHERE fullname = ?"

	sql := `INSERT INTO sys_menu
	(id, href, target, icon, hidden, permission, code, name, fullname, genre, ordinal, parent_id, parent_ids, parent_codes, parent_names, leaf, grade, memo, creates, creater, created, modifier, modified, version, deletion, artifical, history)
	VALUES
	(?, ?, NULL, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, NULL, ?, NULL, ?, 0, 0, 0, 0)`

	count, err := db.Query(csql, m.fullname).Int()
	if err != nil {
		logger.Error(err)
		return m
	}
	if count == 0 {
		_, err = db.Exec(sql, m.id, m.href, m.hidden, m.permission, m.code, m.name, m.fullname, m.genre, m.ordinal, m.parentID, m.parentIDs, m.parentCodes, m.parentNames, m.leaf, m.grade, now, now)
		if err != nil {
			logger.Error(err)
			return m
		}
	}
	return m
}

type menu struct {
	id, href, hidden, permission, code, name, fullname, genre, ordinal, parentID, parentIDs, parentCodes, parentNames, leaf, grade string
}
<|endoftext|>


<commit_before>// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package jwalterweatherman

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
)

// Level describes the chosen log level between
// debug and critical.
type Level int

type NotePad struct {
	Handle io.Writer
	Level  Level
	Prefix string
	Logger **log.Logger
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
type Feedback struct{}

const (
	LevelTrace Level = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelCritical
	LevelFatal
	DefaultLogThreshold    = LevelWarn
	DefaultStdoutThreshold = LevelError
)

var (
	TRACE      *log.Logger
	DEBUG      *log.Logger
	INFO       *log.Logger
	WARN       *log.Logger
	ERROR      *log.Logger
	CRITICAL   *log.Logger
	FATAL      *log.Logger
	LOG        *log.Logger
	FEEDBACK   Feedback
	LogHandle  io.Writer  = ioutil.Discard
	OutHandle  io.Writer  = os.Stdout
	BothHandle io.Writer  = io.MultiWriter(LogHandle, OutHandle)
	NotePads   []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal}

	trace           *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "}
	debug           *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "}
	info            *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "}
	warn            *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "}
	err             *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "}
	critical        *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "}
	fatal           *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "}
	logThreshold    Level    = DefaultLogThreshold
	outputThreshold Level    = DefaultStdoutThreshold

	DATE     = log.Ldate
	TIME     = log.Ltime
	SFILE    = log.Lshortfile
	LFILE    = log.Llongfile
	MSEC     = log.Lmicroseconds
	logFlags = DATE | TIME | SFILE
)

func init() {
	SetStdoutThreshold(DefaultStdoutThreshold)
}

// initialize will setup the jWalterWeatherman standard approach of providing the user
// some feedback and logging a potentially different amount based on independent log and output thresholds.
// By default the output has a lower threshold than logged
// Don't use if you have manually set the Handles of the different levels as it will overwrite them.
func initialize() {
	BothHandle = io.MultiWriter(LogHandle, OutHandle)

	for _, n := range NotePads {
		if n.Level < outputThreshold && n.Level < logThreshold {
			n.Handle = ioutil.Discard
		} else if n.Level >= outputThreshold && n.Level >= logThreshold {
			n.Handle = BothHandle
		} else if n.Level >= outputThreshold && n.Level < logThreshold {
			n.Handle = OutHandle
		} else {
			n.Handle = LogHandle
		}
	}

	for _, n := range NotePads {
		*n.Logger = log.New(n.Handle, n.Prefix, logFlags)
	}

	LOG = log.New(LogHandle,
		"LOG:   ",
		logFlags)
}

// Set the log Flags (Available flag: DATE, TIME, SFILE, LFILE and MSEC)
func SetLogFlag(flags int) {
	logFlags = flags
}

// Level returns the current global log threshold.
func LogThreshold() Level {
	return logThreshold
}

// Level returns the current global output threshold.
func StdoutThreshold() Level {
	return outputThreshold
}

// Ensures that the level provided is within the bounds of available levels
func levelCheck(level Level) Level {
	switch {
	case level <= LevelTrace:
		return LevelTrace
	case level >= LevelFatal:
		return LevelFatal
	default:
		return level
	}
}

// Establishes a threshold where anything matching or above will be logged
func SetLogThreshold(level Level) {
	logThreshold = levelCheck(level)
	initialize()
}

// Establishes a threshold where anything matching or above will be output
func SetStdoutThreshold(level Level) {
	outputThreshold = levelCheck(level)
	initialize()
}

// Conveniently Sets the Log Handle to a io.writer created for the file behind the given filepath
// Will only append to this file
func SetLogFile(path string) {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		CRITICAL.Println("Failed to open log file:", path, err)
		os.Exit(-1)
	}

	INFO.Println("Logging to", file.Name())

	LogHandle = file
	initialize()
}

// Conveniently Creates a temporary file and sets the Log Handle to a io.writer created for it
func UseTempLogFile(prefix string) {
	file, err := ioutil.TempFile(os.TempDir(), prefix)
	if err != nil {
		CRITICAL.Println(err)
	}

	INFO.Println("Logging to", file.Name())

	LogHandle = file
	initialize()
}

// Disables logging for the entire JWW system
func DiscardLogging() {
	LogHandle = ioutil.Discard
	initialize()
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Println(v ...interface{}) {
	s := fmt.Sprintln(v...)
	fmt.Print(s)
	LOG.Output(2, s)
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Printf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	fmt.Print(s)
	LOG.Output(2, s)
}
<commit_msg>Declare logFlags constants as... const!<commit_after>// Copyright © 2014 Steve Francia <spf@spf13.com>.
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

package jwalterweatherman

import (
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
)

// Level describes the chosen log level between
// debug and critical.
type Level int

type NotePad struct {
	Handle io.Writer
	Level  Level
	Prefix string
	Logger **log.Logger
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
type Feedback struct{}

const (
	LevelTrace Level = iota
	LevelDebug
	LevelInfo
	LevelWarn
	LevelError
	LevelCritical
	LevelFatal
	DefaultLogThreshold    = LevelWarn
	DefaultStdoutThreshold = LevelError
)

var (
	TRACE      *log.Logger
	DEBUG      *log.Logger
	INFO       *log.Logger
	WARN       *log.Logger
	ERROR      *log.Logger
	CRITICAL   *log.Logger
	FATAL      *log.Logger
	LOG        *log.Logger
	FEEDBACK   Feedback
	LogHandle  io.Writer  = ioutil.Discard
	OutHandle  io.Writer  = os.Stdout
	BothHandle io.Writer  = io.MultiWriter(LogHandle, OutHandle)
	NotePads   []*NotePad = []*NotePad{trace, debug, info, warn, err, critical, fatal}

	trace           *NotePad = &NotePad{Level: LevelTrace, Handle: os.Stdout, Logger: &TRACE, Prefix: "TRACE: "}
	debug           *NotePad = &NotePad{Level: LevelDebug, Handle: os.Stdout, Logger: &DEBUG, Prefix: "DEBUG: "}
	info            *NotePad = &NotePad{Level: LevelInfo, Handle: os.Stdout, Logger: &INFO, Prefix: "INFO: "}
	warn            *NotePad = &NotePad{Level: LevelWarn, Handle: os.Stdout, Logger: &WARN, Prefix: "WARN: "}
	err             *NotePad = &NotePad{Level: LevelError, Handle: os.Stdout, Logger: &ERROR, Prefix: "ERROR: "}
	critical        *NotePad = &NotePad{Level: LevelCritical, Handle: os.Stdout, Logger: &CRITICAL, Prefix: "CRITICAL: "}
	fatal           *NotePad = &NotePad{Level: LevelFatal, Handle: os.Stdout, Logger: &FATAL, Prefix: "FATAL: "}
	logThreshold    Level    = DefaultLogThreshold
	outputThreshold Level    = DefaultStdoutThreshold
)

const (
	DATE  = log.Ldate
	TIME  = log.Ltime
	SFILE = log.Lshortfile
	LFILE = log.Llongfile
	MSEC  = log.Lmicroseconds
)

var logFlags = DATE | TIME | SFILE

func init() {
	SetStdoutThreshold(DefaultStdoutThreshold)
}

// initialize will setup the jWalterWeatherman standard approach of providing the user
// some feedback and logging a potentially different amount based on independent log and output thresholds.
// By default the output has a lower threshold than logged
// Don't use if you have manually set the Handles of the different levels as it will overwrite them.
func initialize() {
	BothHandle = io.MultiWriter(LogHandle, OutHandle)

	for _, n := range NotePads {
		if n.Level < outputThreshold && n.Level < logThreshold {
			n.Handle = ioutil.Discard
		} else if n.Level >= outputThreshold && n.Level >= logThreshold {
			n.Handle = BothHandle
		} else if n.Level >= outputThreshold && n.Level < logThreshold {
			n.Handle = OutHandle
		} else {
			n.Handle = LogHandle
		}
	}

	for _, n := range NotePads {
		*n.Logger = log.New(n.Handle, n.Prefix, logFlags)
	}

	LOG = log.New(LogHandle,
		"LOG:   ",
		logFlags)
}

// Set the log Flags (Available flag: DATE, TIME, SFILE, LFILE and MSEC)
func SetLogFlag(flags int) {
	logFlags = flags
}

// Level returns the current global log threshold.
func LogThreshold() Level {
	return logThreshold
}

// Level returns the current global output threshold.
func StdoutThreshold() Level {
	return outputThreshold
}

// Ensures that the level provided is within the bounds of available levels
func levelCheck(level Level) Level {
	switch {
	case level <= LevelTrace:
		return LevelTrace
	case level >= LevelFatal:
		return LevelFatal
	default:
		return level
	}
}

// Establishes a threshold where anything matching or above will be logged
func SetLogThreshold(level Level) {
	logThreshold = levelCheck(level)
	initialize()
}

// Establishes a threshold where anything matching or above will be output
func SetStdoutThreshold(level Level) {
	outputThreshold = levelCheck(level)
	initialize()
}

// Conveniently Sets the Log Handle to a io.writer created for the file behind the given filepath
// Will only append to this file
func SetLogFile(path string) {
	file, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		CRITICAL.Println("Failed to open log file:", path, err)
		os.Exit(-1)
	}

	INFO.Println("Logging to", file.Name())

	LogHandle = file
	initialize()
}

// Conveniently Creates a temporary file and sets the Log Handle to a io.writer created for it
func UseTempLogFile(prefix string) {
	file, err := ioutil.TempFile(os.TempDir(), prefix)
	if err != nil {
		CRITICAL.Println(err)
	}

	INFO.Println("Logging to", file.Name())

	LogHandle = file
	initialize()
}

// Disables logging for the entire JWW system
func DiscardLogging() {
	LogHandle = ioutil.Discard
	initialize()
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Println(v ...interface{}) {
	s := fmt.Sprintln(v...)
	fmt.Print(s)
	LOG.Output(2, s)
}

// Feedback is special. It writes plainly to the output while
// logging with the standard extra information (date, file, etc)
// Only Println and Printf are currently provided for this
func (fb *Feedback) Printf(format string, v ...interface{}) {
	s := fmt.Sprintf(format, v...)
	fmt.Print(s)
	LOG.Output(2, s)
}
<|endoftext|>


<commit_before>package response

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/volatile/core"
)

const viewsDir = "views"

var views *template.Template

func init() {
	views = template.New("views")

	// Built-in views funcs
	views.Funcs(template.FuncMap{
		"html":  viewsFuncHTML,
		"nl2br": viewsFuncNL2BR,
	})

	core.BeforeRun(func() {
		if _, err := os.Stat(viewsDir); err == nil {
			err = filepath.Walk(viewsDir, func(path string, f os.FileInfo, err error) error {
				if err != nil {
					return err
				}

				if !f.IsDir() {
					if _, err = views.ParseFiles(path); err != nil {
						return err
					}
				}

				return nil
			})
			if err != nil {
				panic(err)
			}
		}
	})
}

// FuncMap is the type of the map defining the mapping from names to functions.
// Each function must have either a single return value, or two return values of which the second has type error.
// In that case, if the second (error) argument evaluates to non-nil during execution, execution terminates and Execute returns that error.
// FuncMap has the same base type as FuncMap in "text/template", copied here so clients need not import "text/template".
type FuncMap map[string]interface{}

// ViewsFuncs adds a function that will be available to all templates.
func ViewsFuncs(funcMap FuncMap) {
	views.Funcs(template.FuncMap(funcMap))
}

// Status responds with the given status code.
func Status(c *core.Context, v int) {
	http.Error(c.ResponseWriter, http.StatusText(v), v)
}

// String responds with the given string.
func String(c *core.Context, s string) {
	c.ResponseWriter.Write([]byte(s))
}

// Bytes responds with the given slice of byte.
func Bytes(c *core.Context, b []byte) {
	c.ResponseWriter.Write(b)
}

// JSON set the correct header and responds with the marshalled content.
func JSON(c *core.Context, v interface{}) {
	c.ResponseWriter.Header().Set("Content-Type", "application/json")

	var js []byte
	var err error

	if core.Production {
		js, err = json.Marshal(v)
	} else {
		js, err = json.MarshalIndent(v, "", "\t")
	}

	if err != nil {
		log.Println(err)
		http.Error(c.ResponseWriter, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	c.ResponseWriter.Write(js)
}

// View pass the data to the template associated to name, and responds with it.
func View(c *core.Context, name string, data map[string]interface{}) {
	data["c"] = c
	err := views.ExecuteTemplate(c.ResponseWriter, name, data)
	if err != nil {
		log.Println(err)
		http.Error(c.ResponseWriter, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}
}
<commit_msg>Improve readability of helper.go<commit_after>package response

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/volatile/core"
)

const viewsDir = "views"

var views *template.Template

func init() {
	views = template.New("views")

	// Built-in views funcs
	views.Funcs(template.FuncMap{
		"html":  viewsFuncHTML,
		"nl2br": viewsFuncNL2BR,
	})

	core.BeforeRun(func() {
		if _, err := os.Stat(viewsDir); err != nil {
			return
		}

		if err := filepath.Walk(viewsDir, walk); err != nil {
			panic(err)
		}
	})
}

// walk is the path/filepath.WalkFunc that is used to walk viewsDir in order to initialize
// views. It will try to parse all files it encounters and recurse into subdirectories.
func walk(path string, f os.FileInfo, err error) error {
	if err != nil {
		return err
	}

	if f.IsDir() {
		return nil
	}

	_, err = views.ParseFiles(path)

	return err
}

// FuncMap is the type of the map defining the mapping from names to functions.
// Each function must have either a single return value, or two return values of which the second has type error.
// In that case, if the second (error) argument evaluates to non-nil during execution, execution terminates and Execute returns that error.
// FuncMap has the same base type as FuncMap in "text/template", copied here so clients need not import "text/template".
type FuncMap map[string]interface{}

// ViewsFuncs adds a function that will be available to all templates.
func ViewsFuncs(funcMap FuncMap) {
	views.Funcs(template.FuncMap(funcMap))
}

// Status responds with the given status code.
func Status(c *core.Context, v int) {
	http.Error(c.ResponseWriter, http.StatusText(v), v)
}

// String responds with the given string.
func String(c *core.Context, s string) {
	c.ResponseWriter.Write([]byte(s))
}

// Bytes responds with the given slice of byte.
func Bytes(c *core.Context, b []byte) {
	c.ResponseWriter.Write(b)
}

// JSON set the correct header and responds with the marshalled content.
func JSON(c *core.Context, v interface{}) {
	c.ResponseWriter.Header().Set("Content-Type", "application/json")

	var js []byte
	var err error

	if core.Production {
		js, err = json.Marshal(v)
	} else {
		js, err = json.MarshalIndent(v, "", "\t")
	}

	if err != nil {
		log.Println(err)
		http.Error(c.ResponseWriter, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
		return
	}

	c.ResponseWriter.Write(js)
}

// View pass the data to the template associated to name, and responds with it.
func View(c *core.Context, name string, data map[string]interface{}) {
	data["c"] = c
	err := views.ExecuteTemplate(c.ResponseWriter, name, data)
	if err != nil {
		log.Println(err)
		http.Error(c.ResponseWriter, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
	}
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 managedwriter

// [START bigquerystorage_write_pending_complexschema]

import (
	"context"
	"fmt"
	"io"
	"math/rand"
	"time"

	"cloud.google.com/go/bigquery/storage/managedwriter"
	"cloud.google.com/go/bigquery/storage/managedwriter/adapt"
	"github.com/GoogleCloudPlatform/golang-samples/bigquery/snippets/managedwriter/exampleproto"
	storagepb "google.golang.org/genproto/googleapis/cloud/bigquery/storage/v1"
	"google.golang.org/protobuf/proto"
)

// generateExampleMessage generates an example protobuf message using a statically defined and
// compiled protocol buffer file, and returns the binary serialized representation.
func generateExampleMessage() ([]byte, error) {

	random := rand.New(rand.NewSource(time.Now().UnixNano()))

	// Our example data embeds an array of structs, so we'll construct that first.
	sList := make([]*exampleproto.SampleStruct, 5)
	for i := 0; i < int(random.Int63n(5)+1); i++ {
		sList[i] = &exampleproto.SampleStruct{
			SubIntCol: proto.Int64(random.Int63()),
		}
	}

	m := &exampleproto.SampleData{
		BoolCol:    proto.Bool(true),
		BytesCol:   []byte("some bytes"),
		Float64Col: proto.Float64(3.14),
		Int64Col:   proto.Int64(123),
		StringCol:  proto.String("example string value"),

		// These types require special encoding/formatting to transmit.

		// DATE values are number of days since the Unix epoch.
		DateCol: proto.Int32(int32(time.Now().UnixMilli() / 86400000)),

		// DATETIME uses the literal format.
		DatetimeCol: proto.String("2022-01-01 12:13:14.000000"),

		// GEOGRAPHY uses Well-Known-Text (WKT) format.
		GeographyCol: proto.String("POINT(-122.350220 47.649154)"),

		// NUMERIC and BIGNUMERIC can be passed as string, or more efficiently
		// using a packed byte representation.
		NumericCol:    proto.String("99999999999999999999999999999.999999999"),
		BignumericCol: proto.String("578960446186580977117854925043439539266.34992332820282019728792003956564819967"),

		// TIME also uses literal format.
		TimeCol: proto.String("12:13:14.000000"),

		// TIMESTAMP uses microseconds since Unix epoch.
		TimestampCol: proto.Int64(time.Now().UnixMicro()),

		// Int64List is an array of INT64 types.
		Int64List: []int64{2, 4, 6, 8},

		// This is a required field, and thus must be present.
		RowNum: proto.Int64(23),

		// StructCol is a single nested message.
		StructCol: &exampleproto.SampleStruct{
			SubIntCol: proto.Int64(random.Int63()),
		},

		// StructList is a repeated array of a nested message.
		StructList: sList,
	}

	// Now that the protocol message has been populated, serialize it to binary form and return.
	return proto.Marshal(m)
}

// appendToPendingStream demonstrates using the managedwriter package to write some example data
// to a pending stream, and then committing it to a table.
func appendToPendingStream(w io.Writer, projectID, datasetID, tableID string) error {
	// projectID := "myproject"
	// datasetID := "mydataset"
	// tableID := "mytable"

	ctx := context.Background()
	client, err := managedwriter.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("managedwriter.NewClient: %v", err)
	}

	// Create a new pending stream.  We'll use the stream name to construct a writer.
	pendingStream, err := client.CreateWriteStream(ctx, &storagepb.CreateWriteStreamRequest{
		Parent: fmt.Sprintf("projects/%s/datasets/%s/tables/%s", projectID, datasetID, tableID),
		WriteStream: &storagepb.WriteStream{
			Type: storagepb.WriteStream_PENDING,
		},
	})
	if err != nil {
		return fmt.Errorf("CreateWriteStream: %v", err)
	}

	// We need to communicate the descriptor of the protocol buffer message we're using, which
	// is analagous to the "schema" for the message.  Both SampleData and SampleStruct are
	// two distinct messages in the compiled proto file, so we'll use adapt.NormalizeDescriptor
	// to unify them into a single self-contained descriptor representation.
	m := &exampleproto.SampleData{}
	descriptorProto, err := adapt.NormalizeDescriptor(m.ProtoReflect().Descriptor())
	if err != nil {
		return fmt.Errorf("NormalizeDescriptor: %v", err)
	}

	// Instantiate a ManagedStream, which manages low level details like connection state and provides
	// additional features like a future-like callback for appends, etc.  NewManagedStream can also create
	// the stream on your behalf, but in this example we're being explicit about stream creation.
	managedStream, err := client.NewManagedStream(ctx, managedwriter.WithStreamName(pendingStream.GetName()),
		managedwriter.WithSchemaDescriptor(descriptorProto))
	if err != nil {
		return fmt.Errorf("NewManagedStream: %v", err)
	}

	// First, we'll append a single row.
	rowBytes, err := generateExampleMessage()
	if err != nil {
		return fmt.Errorf("generateExampleMessage: %v", err)
	}

	// We'll keep track of the current offset in the stream with curOffset.
	var curOffset int64
	// We can append data asyncronously, so we'll check our appends at the end.
	var results []*managedwriter.AppendResult

	result, err := managedStream.AppendRows(ctx, [][]byte{rowBytes}, managedwriter.WithOffset(0))
	if err != nil {
		return fmt.Errorf("AppendRows first call error: %v", err)
	}
	results = append(results, result)

	// Advance our current offset.
	curOffset = curOffset + 1

	// This time, we'll append three more rows in a single request.
	result, err = managedStream.AppendRows(ctx, [][]byte{rowBytes, rowBytes, rowBytes}, managedwriter.WithOffset(curOffset))
	if err != nil {
		return fmt.Errorf("AppendRows second call error: %v", err)
	}
	results = append(results, result)

	// Advance our offset again.
	curOffset = curOffset + 3

	// Finally, we'll append two more rows.
	result, err = managedStream.AppendRows(ctx, [][]byte{rowBytes, rowBytes, rowBytes}, managedwriter.WithOffset(curOffset))
	if err != nil {
		return fmt.Errorf("AppendRows third call error: %v", err)
	}
	results = append(results, result)

	// Now, we'll check that our batch of three appends all completed successfully.
	// Monitoring the results could also be done out of band via a goroutine.
	for k, v := range results {
		// GetResult blocks until we receive a response from the API.
		recvOffset, err := v.GetResult(ctx)
		if err != nil {
			return fmt.Errorf("append %d returned error: %v", k, err)
		}
		fmt.Fprintf(w, "Successfully appended data at offset %d.\n", recvOffset)
	}

	// We're now done appending to this stream.  We now mark pending stream finalized, which blocks
	// further appends.
	rowCount, err := managedStream.Finalize(ctx)
	if err != nil {
		return fmt.Errorf("error during Finalize: %v", err)
	}

	fmt.Fprintf(w, "Stream %s finalized with %d rows.\n", managedStream.StreamName(), rowCount)

	// To commit the data to the table, we need to run a batch commit.  You can commit several streams
	// atomically as a group, but in this instance we'll only commit the single stream.
	req := &storagepb.BatchCommitWriteStreamsRequest{
		Parent:       managedwriter.TableParentFromStreamName(managedStream.StreamName()),
		WriteStreams: []string{managedStream.StreamName()},
	}

	resp, err := client.BatchCommitWriteStreams(ctx, req)
	if err != nil {
		return fmt.Errorf("client.BatchCommit: %v", err)
	}
	if len(resp.GetStreamErrors()) > 0 {
		return fmt.Errorf("stream errors present: %v", resp.GetStreamErrors())
	}

	fmt.Fprintf(w, "Table data committed at %s\n", resp.GetCommitTime().AsTime().Format(time.RFC3339Nano))

	return nil
}

// [END bigquerystorage_write_pending_complexschema]
<commit_msg>docs: improve managedwriter sample (#2406)<commit_after>// Copyright 2022 Google LLC
//
// 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
//
//     https://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 managedwriter

// [START bigquerystorage_write_pending_complexschema]

import (
	"context"
	"fmt"
	"io"
	"math/rand"
	"time"

	"cloud.google.com/go/bigquery/storage/managedwriter"
	"cloud.google.com/go/bigquery/storage/managedwriter/adapt"
	"github.com/GoogleCloudPlatform/golang-samples/bigquery/snippets/managedwriter/exampleproto"
	storagepb "google.golang.org/genproto/googleapis/cloud/bigquery/storage/v1"
	"google.golang.org/protobuf/proto"
)

// generateExampleMessages generates a slice of serialized protobuf messages using a statically defined
// and compiled protocol buffer file, and returns the binary serialized representation.
func generateExampleMessages(numMessages int) ([][]byte, error) {
	msgs := make([][]byte, numMessages)
	for i := 0; i < numMessages; i++ {

		random := rand.New(rand.NewSource(time.Now().UnixNano()))

		// Our example data embeds an array of structs, so we'll construct that first.
		sList := make([]*exampleproto.SampleStruct, 5)
		for i := 0; i < int(random.Int63n(5)+1); i++ {
			sList[i] = &exampleproto.SampleStruct{
				SubIntCol: proto.Int64(random.Int63()),
			}
		}

		m := &exampleproto.SampleData{
			BoolCol:    proto.Bool(true),
			BytesCol:   []byte("some bytes"),
			Float64Col: proto.Float64(3.14),
			Int64Col:   proto.Int64(123),
			StringCol:  proto.String("example string value"),

			// These types require special encoding/formatting to transmit.

			// DATE values are number of days since the Unix epoch.

			DateCol: proto.Int32(int32(time.Now().UnixNano() / 86400000000000)),

			// DATETIME uses the literal format.
			DatetimeCol: proto.String("2022-01-01 12:13:14.000000"),

			// GEOGRAPHY uses Well-Known-Text (WKT) format.
			GeographyCol: proto.String("POINT(-122.350220 47.649154)"),

			// NUMERIC and BIGNUMERIC can be passed as string, or more efficiently
			// using a packed byte representation.
			NumericCol:    proto.String("99999999999999999999999999999.999999999"),
			BignumericCol: proto.String("578960446186580977117854925043439539266.34992332820282019728792003956564819967"),

			// TIME also uses literal format.
			TimeCol: proto.String("12:13:14.000000"),

			// TIMESTAMP uses microseconds since Unix epoch.
			TimestampCol: proto.Int64(time.Now().UnixNano() / 1000),

			// Int64List is an array of INT64 types.
			Int64List: []int64{2, 4, 6, 8},

			// This is a required field, and thus must be present.
			RowNum: proto.Int64(23),

			// StructCol is a single nested message.
			StructCol: &exampleproto.SampleStruct{
				SubIntCol: proto.Int64(random.Int63()),
			},

			// StructList is a repeated array of a nested message.
			StructList: sList,
		}

		b, err := proto.Marshal(m)
		if err != nil {
			return nil, fmt.Errorf("error generating message %d: %v", i, err)
		}
		msgs[i] = b
	}
	return msgs, nil
}

// appendToPendingStream demonstrates using the managedwriter package to write some example data
// to a pending stream, and then committing it to a table.
func appendToPendingStream(w io.Writer, projectID, datasetID, tableID string) error {
	// projectID := "myproject"
	// datasetID := "mydataset"
	// tableID := "mytable"

	ctx := context.Background()
	client, err := managedwriter.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("managedwriter.NewClient: %v", err)
	}

	// Create a new pending stream.  We'll use the stream name to construct a writer.
	pendingStream, err := client.CreateWriteStream(ctx, &storagepb.CreateWriteStreamRequest{
		Parent: fmt.Sprintf("projects/%s/datasets/%s/tables/%s", projectID, datasetID, tableID),
		WriteStream: &storagepb.WriteStream{
			Type: storagepb.WriteStream_PENDING,
		},
	})
	if err != nil {
		return fmt.Errorf("CreateWriteStream: %v", err)
	}

	// We need to communicate the descriptor of the protocol buffer message we're using, which
	// is analagous to the "schema" for the message.  Both SampleData and SampleStruct are
	// two distinct messages in the compiled proto file, so we'll use adapt.NormalizeDescriptor
	// to unify them into a single self-contained descriptor representation.
	m := &exampleproto.SampleData{}
	descriptorProto, err := adapt.NormalizeDescriptor(m.ProtoReflect().Descriptor())
	if err != nil {
		return fmt.Errorf("NormalizeDescriptor: %v", err)
	}

	// Instantiate a ManagedStream, which manages low level details like connection state and provides
	// additional features like a future-like callback for appends, etc.  NewManagedStream can also create
	// the stream on your behalf, but in this example we're being explicit about stream creation.
	managedStream, err := client.NewManagedStream(ctx, managedwriter.WithStreamName(pendingStream.GetName()),
		managedwriter.WithSchemaDescriptor(descriptorProto))
	if err != nil {
		return fmt.Errorf("NewManagedStream: %v", err)
	}

	// First, we'll append a single row.
	rows, err := generateExampleMessages(1)
	if err != nil {
		return fmt.Errorf("generateExampleMessages: %v", err)
	}

	// We'll keep track of the current offset in the stream with curOffset.
	var curOffset int64
	// We can append data asyncronously, so we'll check our appends at the end.
	var results []*managedwriter.AppendResult

	result, err := managedStream.AppendRows(ctx, rows, managedwriter.WithOffset(0))
	if err != nil {
		return fmt.Errorf("AppendRows first call error: %v", err)
	}
	results = append(results, result)

	// Advance our current offset.
	curOffset = curOffset + 1

	// This time, we'll append three more rows in a single request.
	rows, err = generateExampleMessages(3)
	if err != nil {
		return fmt.Errorf("generateExampleMessages: %v", err)
	}
	result, err = managedStream.AppendRows(ctx, rows, managedwriter.WithOffset(curOffset))
	if err != nil {
		return fmt.Errorf("AppendRows second call error: %v", err)
	}
	results = append(results, result)

	// Advance our offset again.
	curOffset = curOffset + 3

	// Finally, we'll append two more rows.
	rows, err = generateExampleMessages(2)
	if err != nil {
		return fmt.Errorf("generateExampleMessages: %v", err)
	}
	result, err = managedStream.AppendRows(ctx, rows, managedwriter.WithOffset(curOffset))
	if err != nil {
		return fmt.Errorf("AppendRows third call error: %v", err)
	}
	results = append(results, result)

	// Now, we'll check that our batch of three appends all completed successfully.
	// Monitoring the results could also be done out of band via a goroutine.
	for k, v := range results {
		// GetResult blocks until we receive a response from the API.
		recvOffset, err := v.GetResult(ctx)
		if err != nil {
			return fmt.Errorf("append %d returned error: %v", k, err)
		}
		fmt.Fprintf(w, "Successfully appended data at offset %d.\n", recvOffset)
	}

	// We're now done appending to this stream.  We now mark pending stream finalized, which blocks
	// further appends.
	rowCount, err := managedStream.Finalize(ctx)
	if err != nil {
		return fmt.Errorf("error during Finalize: %v", err)
	}

	fmt.Fprintf(w, "Stream %s finalized with %d rows.\n", managedStream.StreamName(), rowCount)

	// To commit the data to the table, we need to run a batch commit.  You can commit several streams
	// atomically as a group, but in this instance we'll only commit the single stream.
	req := &storagepb.BatchCommitWriteStreamsRequest{
		Parent:       managedwriter.TableParentFromStreamName(managedStream.StreamName()),
		WriteStreams: []string{managedStream.StreamName()},
	}

	resp, err := client.BatchCommitWriteStreams(ctx, req)
	if err != nil {
		return fmt.Errorf("client.BatchCommit: %v", err)
	}
	if len(resp.GetStreamErrors()) > 0 {
		return fmt.Errorf("stream errors present: %v", resp.GetStreamErrors())
	}

	fmt.Fprintf(w, "Table data committed at %s\n", resp.GetCommitTime().AsTime().Format(time.RFC3339Nano))

	return nil
}

// [END bigquerystorage_write_pending_complexschema]
<|endoftext|>


<commit_before>// 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 coder

import (
	"bytes"
	"math"
	"testing"

	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/typex"
)

func makePaneInfo(timing typex.PaneTiming, first, last bool, index, nsIndex int64) typex.PaneInfo {
	return typex.PaneInfo{Timing: timing, IsFirst: first, IsLast: last, Index: index, NonSpeculativeIndex: nsIndex}
}

func equalPanes(left, right typex.PaneInfo) bool {
	return (left.Timing == right.Timing) && (left.IsFirst == right.IsFirst) && (left.IsLast == right.IsLast) && (left.Index == right.Index) && (left.NonSpeculativeIndex == right.NonSpeculativeIndex)
}

func TestPaneCoder(t *testing.T) {
	tests := []struct {
		name    string
		timing  typex.PaneTiming
		first   bool
		last    bool
		index   int64
		nsIndex int64
	}{
		{
			"false bools",
			typex.PaneUnknown,
			false,
			false,
			0,
			0,
		},
		{
			"true bools",
			typex.PaneUnknown,
			true,
			true,
			0,
			0,
		},
		{
			"first pane",
			typex.PaneUnknown,
			true,
			false,
			0,
			0,
		},
		{
			"last pane",
			typex.PaneUnknown,
			false,
			true,
			0,
			0,
		},
		{
			"on time, different index and non-speculative",
			typex.PaneOnTime,
			false,
			false,
			1,
			2,
		},
		{
			"valid early pane",
			typex.PaneEarly,
			true,
			false,
			math.MaxInt64,
			-1,
		},
		{
			"on time, max non-speculative index",
			typex.PaneOnTime,
			false,
			true,
			0,
			math.MaxInt64,
		},
		{
			"late pane, max index",
			typex.PaneLate,
			false,
			false,
			math.MaxInt64,
			0,
		},
		{
			"on time, min non-speculative index",
			typex.PaneOnTime,
			false,
			true,
			0,
			math.MinInt64,
		},
		{
			"late, min index",
			typex.PaneLate,
			false,
			false,
			math.MinInt64,
			0,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			input := makePaneInfo(test.timing, test.first, test.last, test.index, test.nsIndex)
			var buf bytes.Buffer
			err := EncodePane(input, &buf)
			if err != nil {
				t.Fatalf("failed to encode pane %v, got %v", input, err)
			}
			got, err := DecodePane(&buf)
			if err != nil {
				t.Fatalf("failed to decode pane from buffer %v, got %v", buf, err)
			}
			if want := input; !equalPanes(got, want) {
				t.Errorf("got pane %v, want %v", got, want)
			}
		})
	}
}

func TestEncodePane_bad(t *testing.T) {
	tests := []struct {
		name    string
		timing  typex.PaneTiming
		first   bool
		last    bool
		index   int64
		nsIndex int64
	}{
		{
			"invalid early pane, max ints",
			typex.PaneEarly,
			true,
			false,
			math.MaxInt64,
			math.MaxInt64,
		},
		{
			"invalid early pane, min ints",
			typex.PaneEarly,
			true,
			false,
			math.MinInt64,
			math.MinInt64,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			input := makePaneInfo(test.timing, test.first, test.last, test.index, test.nsIndex)
			var buf bytes.Buffer
			err := EncodePane(input, &buf)
			if err == nil {
				t.Errorf("successfully encoded pane when it should have failed, got %v", buf)
			}
		})
	}
}
<commit_msg>fixes copy by value error for bytes.Buffer in Error (#17469)<commit_after>// 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 coder

import (
	"bytes"
	"math"
	"testing"

	"github.com/apache/beam/sdks/v2/go/pkg/beam/core/typex"
)

func makePaneInfo(timing typex.PaneTiming, first, last bool, index, nsIndex int64) typex.PaneInfo {
	return typex.PaneInfo{Timing: timing, IsFirst: first, IsLast: last, Index: index, NonSpeculativeIndex: nsIndex}
}

func equalPanes(left, right typex.PaneInfo) bool {
	return (left.Timing == right.Timing) && (left.IsFirst == right.IsFirst) && (left.IsLast == right.IsLast) && (left.Index == right.Index) && (left.NonSpeculativeIndex == right.NonSpeculativeIndex)
}

func TestPaneCoder(t *testing.T) {
	tests := []struct {
		name    string
		timing  typex.PaneTiming
		first   bool
		last    bool
		index   int64
		nsIndex int64
	}{
		{
			"false bools",
			typex.PaneUnknown,
			false,
			false,
			0,
			0,
		},
		{
			"true bools",
			typex.PaneUnknown,
			true,
			true,
			0,
			0,
		},
		{
			"first pane",
			typex.PaneUnknown,
			true,
			false,
			0,
			0,
		},
		{
			"last pane",
			typex.PaneUnknown,
			false,
			true,
			0,
			0,
		},
		{
			"on time, different index and non-speculative",
			typex.PaneOnTime,
			false,
			false,
			1,
			2,
		},
		{
			"valid early pane",
			typex.PaneEarly,
			true,
			false,
			math.MaxInt64,
			-1,
		},
		{
			"on time, max non-speculative index",
			typex.PaneOnTime,
			false,
			true,
			0,
			math.MaxInt64,
		},
		{
			"late pane, max index",
			typex.PaneLate,
			false,
			false,
			math.MaxInt64,
			0,
		},
		{
			"on time, min non-speculative index",
			typex.PaneOnTime,
			false,
			true,
			0,
			math.MinInt64,
		},
		{
			"late, min index",
			typex.PaneLate,
			false,
			false,
			math.MinInt64,
			0,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			input := makePaneInfo(test.timing, test.first, test.last, test.index, test.nsIndex)
			var buf bytes.Buffer
			err := EncodePane(input, &buf)
			if err != nil {
				t.Fatalf("failed to encode pane %v, got %v", input, err)
			}
			got, err := DecodePane(&buf)
			if err != nil {
				t.Fatalf("failed to decode pane from buffer %v, got %v", &buf, err)
			}
			if want := input; !equalPanes(got, want) {
				t.Errorf("got pane %v, want %v", got, want)
			}
		})
	}
}

func TestEncodePane_bad(t *testing.T) {
	tests := []struct {
		name    string
		timing  typex.PaneTiming
		first   bool
		last    bool
		index   int64
		nsIndex int64
	}{
		{
			"invalid early pane, max ints",
			typex.PaneEarly,
			true,
			false,
			math.MaxInt64,
			math.MaxInt64,
		},
		{
			"invalid early pane, min ints",
			typex.PaneEarly,
			true,
			false,
			math.MinInt64,
			math.MinInt64,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			input := makePaneInfo(test.timing, test.first, test.last, test.index, test.nsIndex)
			var buf bytes.Buffer
			err := EncodePane(input, &buf)
			if err == nil {
				t.Errorf("successfully encoded pane when it should have failed, got %v", &buf)
			}
		})
	}
}
<|endoftext|>


<commit_before>// Copyright (c) OpenFaaS Author(s). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package handlers

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/openfaas/faas/gateway/types"
)

// functionMatcher parses out the service name (group 1) and rest of path (group 2).
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")

// Indices and meta-data for functionMatcher regex parts
const (
	hasPathCount = 3
	routeIndex   = 0 // routeIndex corresponds to /function/ or /async-function/
	nameIndex    = 1 // nameIndex is the function name
	pathIndex    = 2 // pathIndex is the path i.e. /employee/:id/
)

// BaseURLResolver URL resolver for upstream requests
type BaseURLResolver interface {
	Resolve(r *http.Request) string
}

// URLPathTransformer Transform the incoming URL path for upstream requests
type URLPathTransformer interface {
	Transform(r *http.Request) string
}

// MakeForwardingProxyHandler create a handler which forwards HTTP requests
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy, notifiers []HTTPNotifier, baseURLResolver BaseURLResolver, urlPathTransformer URLPathTransformer) http.HandlerFunc {

	writeRequestURI := false
	if _, exists := os.LookupEnv("write_request_uri"); exists {
		writeRequestURI = exists
	}

	return func(w http.ResponseWriter, r *http.Request) {
		baseURL := baseURLResolver.Resolve(r)
		originalURL := r.URL.String()

		requestURL := urlPathTransformer.Transform(r)

		start := time.Now()

		statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI)

		seconds := time.Since(start)
		if err != nil {
			log.Printf("error with upstream request to: %s, %s\n", requestURL, err.Error())
		}

		// defer func() {
		for _, notifier := range notifiers {
			notifier.Notify(r.Method, requestURL, originalURL, statusCode, seconds)
		}
		// }()

	}
}

func buildUpstreamRequest(r *http.Request, baseURL string, requestURL string) *http.Request {
	url := baseURL + requestURL

	if len(r.URL.RawQuery) > 0 {
		url = fmt.Sprintf("%s?%s", url, r.URL.RawQuery)
	}

	upstreamReq, _ := http.NewRequest(r.Method, url, nil)

	copyHeaders(upstreamReq.Header, &r.Header)
	deleteHeaders(&upstreamReq.Header, &hopHeaders)

	if len(r.Host) > 0 && upstreamReq.Header.Get("X-Forwarded-Host") == "" {
		upstreamReq.Header["X-Forwarded-Host"] = []string{r.Host}
	}
	if upstreamReq.Header.Get("X-Forwarded-For") == "" {
		upstreamReq.Header["X-Forwarded-For"] = []string{r.RemoteAddr}
	}

	if r.Body != nil {
		upstreamReq.Body = r.Body
	}

	return upstreamReq
}

func forwardRequest(w http.ResponseWriter, r *http.Request, proxyClient *http.Client, baseURL string, requestURL string, timeout time.Duration, writeRequestURI bool) (int, error) {

	upstreamReq := buildUpstreamRequest(r, baseURL, requestURL)
	if upstreamReq.Body != nil {
		defer upstreamReq.Body.Close()
	}

	if writeRequestURI {
		log.Printf("forwardRequest: %s %s\n", upstreamReq.Host, upstreamReq.URL.String())
	}

	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	res, resErr := proxyClient.Do(upstreamReq.WithContext(ctx))
	if resErr != nil {
		badStatus := http.StatusBadGateway
		w.WriteHeader(badStatus)
		return badStatus, resErr
	}

	if res.Body != nil {
		defer res.Body.Close()
	}

	copyHeaders(w.Header(), &res.Header)

	// Write status code
	w.WriteHeader(res.StatusCode)

	if res.Body != nil {
		// Copy the body over
		io.CopyBuffer(w, res.Body, nil)
	}

	return res.StatusCode, nil
}

func copyHeaders(destination http.Header, source *http.Header) {
	for k, v := range *source {
		vClone := make([]string, len(v))
		copy(vClone, v)
		(destination)[k] = vClone
	}
}

func deleteHeaders(target *http.Header, exclude *[]string) {
	for _, h := range *exclude {
		target.Del(h)
	}
}

// SingleHostBaseURLResolver resolves URLs against a single BaseURL
type SingleHostBaseURLResolver struct {
	BaseURL string
}

// Resolve the base URL for a request
func (s SingleHostBaseURLResolver) Resolve(r *http.Request) string {

	baseURL := s.BaseURL

	if strings.HasSuffix(baseURL, "/") {
		baseURL = baseURL[0 : len(baseURL)-1]
	}
	return baseURL
}

// FunctionAsHostBaseURLResolver resolves URLs using a function from the URL as a host
type FunctionAsHostBaseURLResolver struct {
	FunctionSuffix string
}

// Resolve the base URL for a request
func (f FunctionAsHostBaseURLResolver) Resolve(r *http.Request) string {
	svcName := getServiceName(r.URL.Path)

	const watchdogPort = 8080
	var suffix string
	if len(f.FunctionSuffix) > 0 {
		suffix = "." + f.FunctionSuffix
	}

	return fmt.Sprintf("http://%s%s:%d", svcName, suffix, watchdogPort)
}

// TransparentURLPathTransformer passes the requested URL path through untouched.
type TransparentURLPathTransformer struct {
}

// Transform returns the URL path unchanged.
func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
	return r.URL.Path
}

// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
type FunctionPrefixTrimmingURLPathTransformer struct {
}

// Transform removes the "/function/servicename/" prefix from the URL path.
func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) string {
	ret := r.URL.Path

	if ret != "" {
		// When forwarding to a function, since the `/function/xyz` portion
		// of a path like `/function/xyz/rest/of/path` is only used or needed
		// by the Gateway, we want to trim it down to `/rest/of/path` for the
		// upstream request.  In the following regex, in the case of a match
		// the r.URL.Path will be at `0`, the function name at `1` and the
		// rest of the path (the part we are interested in) at `2`.
		matcher := functionMatcher.Copy()
		parts := matcher.FindStringSubmatch(ret)
		if len(parts) == hasPathCount {
			ret = parts[pathIndex]
		}
	}

	return ret
}

// Hop-by-hop headers. These are removed when sent to the backend.
// As of RFC 7230, hop-by-hop headers are required to appear in the
// Connection header field. These are the headers defined by the
// obsoleted RFC 2616 (section 13.5.1) and are used for backward
// compatibility.
var hopHeaders = []string{
	"Connection",
	"Proxy-Connection", // non-standard but still sent by libcurl and rejected by e.g. google
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te",      // canonicalized version of "TE"
	"Trailer", // not Trailers per URL above; https://www.rfc-editor.org/errata_search.php?eid=4522
	"Transfer-Encoding",
	"Upgrade",
}
<commit_msg>Quote source of hop headers<commit_after>// Copyright (c) OpenFaaS Author(s). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package handlers

import (
	"context"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/openfaas/faas/gateway/types"
)

// functionMatcher parses out the service name (group 1) and rest of path (group 2).
var functionMatcher = regexp.MustCompile("^/?(?:async-)?function/([^/?]+)([^?]*)")

// Indices and meta-data for functionMatcher regex parts
const (
	hasPathCount = 3
	routeIndex   = 0 // routeIndex corresponds to /function/ or /async-function/
	nameIndex    = 1 // nameIndex is the function name
	pathIndex    = 2 // pathIndex is the path i.e. /employee/:id/
)

// BaseURLResolver URL resolver for upstream requests
type BaseURLResolver interface {
	Resolve(r *http.Request) string
}

// URLPathTransformer Transform the incoming URL path for upstream requests
type URLPathTransformer interface {
	Transform(r *http.Request) string
}

// MakeForwardingProxyHandler create a handler which forwards HTTP requests
func MakeForwardingProxyHandler(proxy *types.HTTPClientReverseProxy, notifiers []HTTPNotifier, baseURLResolver BaseURLResolver, urlPathTransformer URLPathTransformer) http.HandlerFunc {

	writeRequestURI := false
	if _, exists := os.LookupEnv("write_request_uri"); exists {
		writeRequestURI = exists
	}

	return func(w http.ResponseWriter, r *http.Request) {
		baseURL := baseURLResolver.Resolve(r)
		originalURL := r.URL.String()

		requestURL := urlPathTransformer.Transform(r)

		start := time.Now()

		statusCode, err := forwardRequest(w, r, proxy.Client, baseURL, requestURL, proxy.Timeout, writeRequestURI)

		seconds := time.Since(start)
		if err != nil {
			log.Printf("error with upstream request to: %s, %s\n", requestURL, err.Error())
		}

		// defer func() {
		for _, notifier := range notifiers {
			notifier.Notify(r.Method, requestURL, originalURL, statusCode, seconds)
		}
		// }()

	}
}

func buildUpstreamRequest(r *http.Request, baseURL string, requestURL string) *http.Request {
	url := baseURL + requestURL

	if len(r.URL.RawQuery) > 0 {
		url = fmt.Sprintf("%s?%s", url, r.URL.RawQuery)
	}

	upstreamReq, _ := http.NewRequest(r.Method, url, nil)

	copyHeaders(upstreamReq.Header, &r.Header)
	deleteHeaders(&upstreamReq.Header, &hopHeaders)

	if len(r.Host) > 0 && upstreamReq.Header.Get("X-Forwarded-Host") == "" {
		upstreamReq.Header["X-Forwarded-Host"] = []string{r.Host}
	}
	if upstreamReq.Header.Get("X-Forwarded-For") == "" {
		upstreamReq.Header["X-Forwarded-For"] = []string{r.RemoteAddr}
	}

	if r.Body != nil {
		upstreamReq.Body = r.Body
	}

	return upstreamReq
}

func forwardRequest(w http.ResponseWriter, r *http.Request, proxyClient *http.Client, baseURL string, requestURL string, timeout time.Duration, writeRequestURI bool) (int, error) {

	upstreamReq := buildUpstreamRequest(r, baseURL, requestURL)
	if upstreamReq.Body != nil {
		defer upstreamReq.Body.Close()
	}

	if writeRequestURI {
		log.Printf("forwardRequest: %s %s\n", upstreamReq.Host, upstreamReq.URL.String())
	}

	ctx, cancel := context.WithTimeout(context.Background(), timeout)
	defer cancel()

	res, resErr := proxyClient.Do(upstreamReq.WithContext(ctx))
	if resErr != nil {
		badStatus := http.StatusBadGateway
		w.WriteHeader(badStatus)
		return badStatus, resErr
	}

	if res.Body != nil {
		defer res.Body.Close()
	}

	copyHeaders(w.Header(), &res.Header)

	// Write status code
	w.WriteHeader(res.StatusCode)

	if res.Body != nil {
		// Copy the body over
		io.CopyBuffer(w, res.Body, nil)
	}

	return res.StatusCode, nil
}

func copyHeaders(destination http.Header, source *http.Header) {
	for k, v := range *source {
		vClone := make([]string, len(v))
		copy(vClone, v)
		(destination)[k] = vClone
	}
}

func deleteHeaders(target *http.Header, exclude *[]string) {
	for _, h := range *exclude {
		target.Del(h)
	}
}

// SingleHostBaseURLResolver resolves URLs against a single BaseURL
type SingleHostBaseURLResolver struct {
	BaseURL string
}

// Resolve the base URL for a request
func (s SingleHostBaseURLResolver) Resolve(r *http.Request) string {

	baseURL := s.BaseURL

	if strings.HasSuffix(baseURL, "/") {
		baseURL = baseURL[0 : len(baseURL)-1]
	}
	return baseURL
}

// FunctionAsHostBaseURLResolver resolves URLs using a function from the URL as a host
type FunctionAsHostBaseURLResolver struct {
	FunctionSuffix string
}

// Resolve the base URL for a request
func (f FunctionAsHostBaseURLResolver) Resolve(r *http.Request) string {
	svcName := getServiceName(r.URL.Path)

	const watchdogPort = 8080
	var suffix string
	if len(f.FunctionSuffix) > 0 {
		suffix = "." + f.FunctionSuffix
	}

	return fmt.Sprintf("http://%s%s:%d", svcName, suffix, watchdogPort)
}

// TransparentURLPathTransformer passes the requested URL path through untouched.
type TransparentURLPathTransformer struct {
}

// Transform returns the URL path unchanged.
func (f TransparentURLPathTransformer) Transform(r *http.Request) string {
	return r.URL.Path
}

// FunctionPrefixTrimmingURLPathTransformer removes the "/function/servicename/" prefix from the URL path.
type FunctionPrefixTrimmingURLPathTransformer struct {
}

// Transform removes the "/function/servicename/" prefix from the URL path.
func (f FunctionPrefixTrimmingURLPathTransformer) Transform(r *http.Request) string {
	ret := r.URL.Path

	if ret != "" {
		// When forwarding to a function, since the `/function/xyz` portion
		// of a path like `/function/xyz/rest/of/path` is only used or needed
		// by the Gateway, we want to trim it down to `/rest/of/path` for the
		// upstream request.  In the following regex, in the case of a match
		// the r.URL.Path will be at `0`, the function name at `1` and the
		// rest of the path (the part we are interested in) at `2`.
		matcher := functionMatcher.Copy()
		parts := matcher.FindStringSubmatch(ret)
		if len(parts) == hasPathCount {
			ret = parts[pathIndex]
		}
	}

	return ret
}

// Hop-by-hop headers. These are removed when sent to the backend.
// As of RFC 7230, hop-by-hop headers are required to appear in the
// Connection header field. These are the headers defined by the
// obsoleted RFC 2616 (section 13.5.1) and are used for backward
// compatibility.
// Copied from: https://golang.org/src/net/http/httputil/reverseproxy.go
var hopHeaders = []string{
	"Connection",
	"Proxy-Connection", // non-standard but still sent by libcurl and rejected by e.g. google
	"Keep-Alive",
	"Proxy-Authenticate",
	"Proxy-Authorization",
	"Te",      // canonicalized version of "TE"
	"Trailer", // not Trailers per URL above; https://www.rfc-editor.org/errata_search.php?eid=4522
	"Transfer-Encoding",
	"Upgrade",
}
<|endoftext|>


<commit_before>package client

import (
	"net"
	"os"
	"testing"
)

type mockNetConn struct {
	*testing.T

	In, Out chan string
	in, out chan []byte

	closed bool
	rt, wt int64
}

func MockNetConn(t *testing.T) (*mockNetConn) {
	// Our mock connection is a testing object
	m := &mockNetConn{T: t}

	// set known values for conn info
	m.closed = false
	m.rt = 0
	m.wt = 0

	// buffer input
	m.In = make(chan string, 20)
	m.in = make(chan []byte)
	go func() {
		for !m.closed {
			m.in <- []byte(<-m.In)
		}
	}()

	// buffer output
	m.Out = make(chan string)
	m.out = make(chan []byte, 20)
	go func() {
		for !m.closed {
			m.Out <- string(<-m.out)
		}
	}()
	return m
}

// Test helper
func (m *mockNetConn) Expect(e string) {
	s := <-m.Out
	if e + "\r\n" != s {
		m.Errorf("Mock connection received unexpected value.\n\t" +
			"Expected: %s\n\tGot: %s", e, s)
	}
}

// Implement net.Conn interface
func (m *mockNetConn) Read(b []byte) (int, os.Error) {
	s := <-m.in
	copy(b, s)
	return len(s), nil
}

func (m *mockNetConn) Write(s []byte) (int, os.Error) {
	b := make([]byte, len(s))
	copy(b, s)
	m.out <- b
	return len(b), nil
}

func (m *mockNetConn) Close() os.Error {
	m.closed = true
	return nil
}

func (m *mockNetConn) LocalAddr() net.Addr {
	return &net.IPAddr{net.IPv4(127,0,0,1)}
}

func (m *mockNetConn) RemoteAddr() net.Addr {
	return &net.IPAddr{net.IPv4(127,0,0,1)}
}

func (m *mockNetConn) SetTimeout(ns int64) os.Error {
	m.rt = ns
	m.wt = ns
	return nil
}

func (m *mockNetConn) SetReadTimeout(ns int64) os.Error {
	m.rt = ns
	return nil
}

func (m *mockNetConn) SetWriteTimeout(ns int64) os.Error {
	m.wt = ns
	return nil
}
<commit_msg>Add Send method for mockNetConn, and make Read/Write return errors when closed.<commit_after>package client

import (
	"net"
	"os"
	"testing"
)

type mockNetConn struct {
	*testing.T

	In, Out chan string
	in, out chan []byte

	closed bool
	rt, wt int64
}

func MockNetConn(t *testing.T) (*mockNetConn) {
	// Our mock connection is a testing object
	m := &mockNetConn{T: t}

	// set known values for conn info
	m.closed = false
	m.rt = 0
	m.wt = 0

	// buffer input
	m.In = make(chan string, 20)
	m.in = make(chan []byte)
	go func() {
		for !m.closed {
			m.in <- []byte(<-m.In)
		}
	}()

	// buffer output
	m.Out = make(chan string)
	m.out = make(chan []byte, 20)
	go func() {
		for !m.closed {
			m.Out <- string(<-m.out)
		}
	}()
	return m
}

// Test helpers
func (m *mockNetConn) Send(s string) {
	m.In <- s + "\r\n"
}

func (m *mockNetConn) Expect(e string) {
	s := <-m.Out
	if e + "\r\n" != s {
		m.Errorf("Mock connection received unexpected value.\n\t" +
			"Expected: %s\n\tGot: %s", e, s)
	}
}

// Implement net.Conn interface
func (m *mockNetConn) Read(b []byte) (int, os.Error) {
	if m.closed {
		return 0, os.NewError("EOF")
	}
	s := <-m.in
	copy(b, s)
	return len(s), nil
}

func (m *mockNetConn) Write(s []byte) (int, os.Error) {
	if m.closed {
		return 0, os.NewError("Can't write to closed socket.")
	}
	b := make([]byte, len(s))
	copy(b, s)
	m.out <- b
	return len(b), nil
}

func (m *mockNetConn) Close() os.Error {
	m.closed = true
	return nil
}

func (m *mockNetConn) LocalAddr() net.Addr {
	return &net.IPAddr{net.IPv4(127,0,0,1)}
}

func (m *mockNetConn) RemoteAddr() net.Addr {
	return &net.IPAddr{net.IPv4(127,0,0,1)}
}

func (m *mockNetConn) SetTimeout(ns int64) os.Error {
	m.rt = ns
	m.wt = ns
	return nil
}

func (m *mockNetConn) SetReadTimeout(ns int64) os.Error {
	m.rt = ns
	return nil
}

func (m *mockNetConn) SetWriteTimeout(ns int64) os.Error {
	m.wt = ns
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 timeutil_test

import (
	"testing"
	"time"

	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/ogletest"
)

func TestTimeEq(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type TimeEqTest struct {
}

func init() { RegisterTestSuite(&TimeEqTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TimeEqTest) Description() {
	expected := time.Now()
	matcher := timeutil.TimeEq(expected)
	ExpectEq(expected.String(), matcher.Description())
}

func (t *TimeEqTest) DoesFoo() {
	AssertTrue(false, "TODO")
}
<commit_msg>Added test names.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 timeutil_test

import (
	"testing"
	"time"

	"github.com/jacobsa/gcsfuse/timeutil"
	. "github.com/jacobsa/ogletest"
)

func TestTimeEq(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type TimeEqTest struct {
}

func init() { RegisterTestSuite(&TimeEqTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *TimeEqTest) Description() {
	expected := time.Now()
	matcher := timeutil.TimeEq(expected)
	ExpectEq(expected.String(), matcher.Description())
}

func (t *TimeEqTest) ActualIsNil() {
	AssertTrue(false, "TODO")
}

func (t *TimeEqTest) ActualIsString() {
	AssertTrue(false, "TODO")
}

func (t *TimeEqTest) ActualIsBeforeExpected() {
	AssertTrue(false, "TODO")
}

func (t *TimeEqTest) ActualIsAfterExpected() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>package tools

import (
	"encoding/gob"
	"fmt"
	"io"
	"os"
	"sync"
)

// KeyValueStore provides an in-memory key/value store which is persisted to
// a file. The file handle itself is not kept locked for the duration; it is
// only locked during load and save, to make it concurrency friendly. When
// saving, the store uses optimistic locking to determine whether the db on disk
// has been modified by another process; in which case it loads the latest
// version and re-applies modifications made during this session. This means
// the Lost Update db concurrency issue is possible; so don't use this if you
// need more DB integrity than Read Committed isolation levels.
type KeyValueStore struct {
	mu       sync.RWMutex
	filename string
	log      []keyValueChange

	// This is the persistent data
	// version for optimistic locking, this field is incremented with every Save()
	version int64
	db      map[string]interface{}
}

type keyValueOperation int

const (
	// Set a value for a key
	keyValueSetOperation = keyValueOperation(iota)
	// Removed a value for a key
	keyValueRemoveOperation = keyValueOperation(iota)
)

type keyValueChange struct {
	operation keyValueOperation
	key       string
	value     interface{}
}

// NewKeyValueStore creates a new store and initialises it with contents from
// the named file, if it exists
func NewKeyValueStore(filepath string) (*KeyValueStore, error) {
	kv := &KeyValueStore{filename: filepath, db: make(map[string]interface{})}
	err := kv.loadAndMergeIfNeeded()
	return kv, err
}

// Set updates the key/value store in memory
// Changes are not persisted until you call Save()
func (k *KeyValueStore) Set(key string, value interface{}) {
	k.mu.Lock()
	defer k.mu.Unlock()

	k.db[key] = value
	k.log = append(k.log, keyValueChange{keyValueSetOperation, key, value})
}

// Remove removes the key and its value from the store in memory
// Changes are not persisted until you call Save()
func (k *KeyValueStore) Remove(key string) {
	k.mu.Lock()
	defer k.mu.Unlock()

	delete(k.db, key)
	k.log = append(k.log, keyValueChange{keyValueRemoveOperation, key, nil})
}

// Get retrieves a value from the store, or nil if it is not present
func (k *KeyValueStore) Get(key string) interface{} {
	// Read-only lock
	k.mu.RLock()
	defer k.mu.RUnlock()

	// zero value of interface{} is nil so this does what we want
	return k.db[key]
}

// Save persists the changes made to disk
// If any changes have been written by other code they will be merged
func (k *KeyValueStore) Save() error {
	k.mu.Lock()
	defer k.mu.Unlock()

	// Short-circuit if we have no changes
	if len(k.log) == 0 {
		return nil
	}

	// firstly peek at version; open read/write to keep lock between check & write
	f, err := os.OpenFile(k.filename, os.O_RDWR|os.O_CREATE, 0664)
	if err != nil {
		return err
	}
	stat, _ := os.Stat(k.filename)

	defer f.Close()

	// Only try to merge if > 0 bytes, ignore empty files (decoder will fail)
	if stat.Size() > 0 {
		k.loadAndMergeReaderIfNeeded(f)
		// Now we overwrite the file
		f.Seek(0, os.SEEK_SET)
		f.Truncate(0)
	}

	k.version++

	enc := gob.NewEncoder(f)
	err = enc.Encode(k.version)
	if err != nil {
		return fmt.Errorf("Error while writing version data to %v: %v", k.filename, err)
	}
	err = enc.Encode(k.db)
	if err != nil {
		return fmt.Errorf("Error while writing new key/value data to %v: %v", k.filename, err)
	}
	// Clear log now that it's saved
	k.log = nil

	return nil
}

// Reads as little as possible from the passed in file to determine if the
// contents are different from the version already held. If so, reads the
// contents and merges with any outstanding changes. If not, stops early without
// reading the rest of the file
func (k *KeyValueStore) loadAndMergeIfNeeded() error {
	stat, err := os.Stat(k.filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // missing is OK
		}
		return err
	}
	// Do nothing if empty file
	if stat.Size() == 0 {
		return nil
	}

	f, err := os.OpenFile(k.filename, os.O_RDONLY, 0664)
	if err == nil {
		defer f.Close()
		return k.loadAndMergeReaderIfNeeded(f)
	} else if !os.IsNotExist(err) {
		return err
	}
	return nil
}

// As loadAndMergeIfNeeded but lets caller decide how to manage file handles
func (k *KeyValueStore) loadAndMergeReaderIfNeeded(f io.Reader) error {
	var versionOnDisk int64
	// Decode *only* the version field to check whether anyone else has
	// modified the db; gob serializes structs in order so it will always be 1st
	dec := gob.NewDecoder(f)
	err := dec.Decode(&versionOnDisk)
	if err != nil {
		return fmt.Errorf("Problem checking version of key/value data from %v: %v", k.filename, err)
	}
	// Totally uninitialised Version == 0, saved versions are always >=1
	if versionOnDisk != k.version {
		// Reload data & merge
		var dbOnDisk map[string]interface{}
		err = dec.Decode(&dbOnDisk)
		if err != nil {
			return fmt.Errorf("Problem reading updated key/value data from %v: %v", k.filename, err)
		}
		k.reapplyChanges(dbOnDisk)
		k.version = versionOnDisk
	}
	return nil
}

// reapplyChanges replays the changes made since the last load onto baseDb
// and stores the result as our own DB
func (k *KeyValueStore) reapplyChanges(baseDb map[string]interface{}) {
	for _, change := range k.log {
		switch change.operation {
		case keyValueSetOperation:
			baseDb[change.key] = change.value
		case keyValueRemoveOperation:
			delete(baseDb, change.key)
		}
	}
	// Note, log is not cleared here, that only happens on Save since it's a
	// list of unsaved changes
	k.db = baseDb

}

// RegisterTypeForKeyValueStorage registers a custom type (e.g. a struct) for
// use in the key value store. This is necessary if you intend to pass custom
// structs to KeyValueStore.Set() rather than primitive types.
func RegisterTypeForKeyValueStorage(val interface{}) {
	gob.Register(val)
}
<commit_msg>PR feedback<commit_after>package tools

import (
	"encoding/gob"
	"fmt"
	"io"
	"os"
	"sync"
)

// KeyValueStore provides an in-memory key/value store which is persisted to
// a file. The file handle itself is not kept locked for the duration; it is
// only locked during load and save, to make it concurrency friendly. When
// saving, the store uses optimistic locking to determine whether the db on disk
// has been modified by another process; in which case it loads the latest
// version and re-applies modifications made during this session. This means
// the Lost Update db concurrency issue is possible; so don't use this if you
// need more DB integrity than Read Committed isolation levels.
type KeyValueStore struct {
	// Locks the entire store
	mu       sync.RWMutex
	filename string
	log      []keyValueChange

	// This is the persistent data
	// version for optimistic locking, this field is incremented with every Save()
	version int64
	db      map[string]interface{}
}

type keyValueOperation int

const (
	// Set a value for a key
	keyValueSetOperation = keyValueOperation(iota)
	// Removed a value for a key
	keyValueRemoveOperation = keyValueOperation(iota)
)

type keyValueChange struct {
	operation keyValueOperation
	key       string
	value     interface{}
}

// NewKeyValueStore creates a new store and initialises it with contents from
// the named file, if it exists
func NewKeyValueStore(filepath string) (*KeyValueStore, error) {
	kv := &KeyValueStore{filename: filepath, db: make(map[string]interface{})}
	return kv, kv.loadAndMergeIfNeeded()
}

// Set updates the key/value store in memory
// Changes are not persisted until you call Save()
func (k *KeyValueStore) Set(key string, value interface{}) {
	k.mu.Lock()
	defer k.mu.Unlock()

	k.db[key] = value
	k.logChange(keyValueSetOperation, key, value)
}

// Remove removes the key and its value from the store in memory
// Changes are not persisted until you call Save()
func (k *KeyValueStore) Remove(key string) {
	k.mu.Lock()
	defer k.mu.Unlock()

	delete(k.db, key)
	k.logChange(keyValueRemoveOperation, key, nil)
}

// Append a change to the log; mutex must already be locked
func (k *KeyValueStore) logChange(op keyValueOperation, key string, value interface{}) {
	k.log = append(k.log, keyValueChange{op, key, value})
}

// Get retrieves a value from the store, or nil if it is not present
func (k *KeyValueStore) Get(key string) interface{} {
	// Read-only lock
	k.mu.RLock()
	defer k.mu.RUnlock()

	// zero value of interface{} is nil so this does what we want
	return k.db[key]
}

// Save persists the changes made to disk
// If any changes have been written by other code they will be merged
func (k *KeyValueStore) Save() error {
	k.mu.Lock()
	defer k.mu.Unlock()

	// Short-circuit if we have no changes
	if len(k.log) == 0 {
		return nil
	}

	// firstly peek at version; open read/write to keep lock between check & write
	f, err := os.OpenFile(k.filename, os.O_RDWR|os.O_CREATE, 0664)
	if err != nil {
		return err
	}
	stat, _ := os.Stat(k.filename)

	defer f.Close()

	// Only try to merge if > 0 bytes, ignore empty files (decoder will fail)
	if stat.Size() > 0 {
		k.loadAndMergeReaderIfNeeded(f)
		// Now we overwrite the file
		f.Seek(0, os.SEEK_SET)
		f.Truncate(0)
	}

	k.version++

	enc := gob.NewEncoder(f)
	if err := enc.Encode(k.version); err != nil {
		return fmt.Errorf("Error while writing version data to %v: %v", k.filename, err)
	}
	if err := enc.Encode(k.db); err != nil {
		return fmt.Errorf("Error while writing new key/value data to %v: %v", k.filename, err)
	}
	// Clear log now that it's saved
	k.log = nil

	return nil
}

// Reads as little as possible from the passed in file to determine if the
// contents are different from the version already held. If so, reads the
// contents and merges with any outstanding changes. If not, stops early without
// reading the rest of the file
func (k *KeyValueStore) loadAndMergeIfNeeded() error {
	stat, err := os.Stat(k.filename)
	if err != nil {
		if os.IsNotExist(err) {
			return nil // missing is OK
		}
		return err
	}
	// Do nothing if empty file
	if stat.Size() == 0 {
		return nil
	}

	f, err := os.OpenFile(k.filename, os.O_RDONLY, 0664)
	if err == nil {
		defer f.Close()
		return k.loadAndMergeReaderIfNeeded(f)
	} else {
		return err
	}
}

// As loadAndMergeIfNeeded but lets caller decide how to manage file handles
func (k *KeyValueStore) loadAndMergeReaderIfNeeded(f io.Reader) error {
	var versionOnDisk int64
	// Decode *only* the version field to check whether anyone else has
	// modified the db; gob serializes structs in order so it will always be 1st
	dec := gob.NewDecoder(f)
	err := dec.Decode(&versionOnDisk)
	if err != nil {
		return fmt.Errorf("Problem checking version of key/value data from %v: %v", k.filename, err)
	}
	// Totally uninitialised Version == 0, saved versions are always >=1
	if versionOnDisk != k.version {
		// Reload data & merge
		var dbOnDisk map[string]interface{}
		err = dec.Decode(&dbOnDisk)
		if err != nil {
			return fmt.Errorf("Problem reading updated key/value data from %v: %v", k.filename, err)
		}
		k.reapplyChanges(dbOnDisk)
		k.version = versionOnDisk
	}
	return nil
}

// reapplyChanges replays the changes made since the last load onto baseDb
// and stores the result as our own DB
func (k *KeyValueStore) reapplyChanges(baseDb map[string]interface{}) {
	for _, change := range k.log {
		switch change.operation {
		case keyValueSetOperation:
			baseDb[change.key] = change.value
		case keyValueRemoveOperation:
			delete(baseDb, change.key)
		}
	}
	// Note, log is not cleared here, that only happens on Save since it's a
	// list of unsaved changes
	k.db = baseDb

}

// RegisterTypeForKeyValueStorage registers a custom type (e.g. a struct) for
// use in the key value store. This is necessary if you intend to pass custom
// structs to KeyValueStore.Set() rather than primitive types.
func RegisterTypeForKeyValueStorage(val interface{}) {
	gob.Register(val)
}
<|endoftext|>


<commit_before>// Package hiprus provides a Hipchat hook for the logrus loggin package.
package hiprus

import (
	"net/url"

	"github.com/Sirupsen/logrus"
	"github.com/tbruyelle/hipchat-go/hipchat"
)

const (
	VERSION     = "2.0.0"
	ColorYellow = "yellow"
	ColorRed    = "red"
	ColorGreen  = "green"
	ColorPurple = "purple"
	ColorGray   = "gray"
	ColorRandom = "random"
)

// HiprusHook is a logrus Hook for dispatching messages to the specified
// channel on Hipchat.
type HiprusHook struct {
	// Messages with a log level not contained in this array
	// will not be dispatched. If nil, all messages will be dispatched.
	AcceptedLevels []logrus.Level
	AuthToken      string
	RoomName       string
	// If empty, "Hiprus" will be used.
	Username string
	// If empty, will point to hipchat cloud
	BaseURL string
	c       *hipchat.Client
}

func (hh *HiprusHook) Levels() []logrus.Level {
	if hh.AcceptedLevels == nil {
		return AllLevels
	}
	return hh.AcceptedLevels
}

func (hh *HiprusHook) Fire(e *logrus.Entry) error {
	if hh.c == nil {
		if err := hh.initClient(); err != nil {
			return err
		}
	}

	color := ""
	notify := false
	switch e.Level {
	case logrus.DebugLevel:
		color = ColorPurple
	case logrus.InfoLevel:
		color = ColorGreen
	case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
		color = ColorRed
		notify = true
	default:
		color = ColorYellow
		notify = true
	}

	_, err := hh.c.Room.Notification(hh.RoomName, &hipchat.NotificationRequest{
		From:          hh.Username,
		Message:       e.Message,
		MessageFormat: "text",
		Notify:        notify,
		Color:         color,
	})

	return err
}

func (hh *HiprusHook) initClient() error {
	c := hipchat.NewClient(hh.AuthToken)

	if hh.BaseURL != "" {
		hipchatUrl, _ := url.Parse(hh.BaseURL)
		c.BaseURL = hipchatUrl
	}

	hh.c = c

	if hh.Username == "" {
		hh.Username = "HipRus"
	}

	return nil
}
<commit_msg>Changing color type to hipchat.Color to fix build errors<commit_after>// Package hiprus provides a Hipchat hook for the logrus loggin package.
package hiprus

import (
	"net/url"

	"github.com/Sirupsen/logrus"
	"github.com/tbruyelle/hipchat-go/hipchat"
)

const (
	VERSION                   = "2.0.0"
	ColorYellow hipchat.Color = "yellow"
	ColorRed    hipchat.Color = "red"
	ColorGreen  hipchat.Color = "green"
	ColorPurple hipchat.Color = "purple"
	ColorGray   hipchat.Color = "gray"
	ColorRandom hipchat.Color = "random"
)

// HiprusHook is a logrus Hook for dispatching messages to the specified
// channel on Hipchat.
type HiprusHook struct {
	// Messages with a log level not contained in this array
	// will not be dispatched. If nil, all messages will be dispatched.
	AcceptedLevels []logrus.Level
	AuthToken      string
	RoomName       string
	// If empty, "Hiprus" will be used.
	Username string
	// If empty, will point to hipchat cloud
	BaseURL string
	c       *hipchat.Client
}

func (hh *HiprusHook) Levels() []logrus.Level {
	if hh.AcceptedLevels == nil {
		return AllLevels
	}
	return hh.AcceptedLevels
}

func (hh *HiprusHook) Fire(e *logrus.Entry) error {
	if hh.c == nil {
		if err := hh.initClient(); err != nil {
			return err
		}
	}

	var color hipchat.Color
	notify := false
	switch e.Level {
	case logrus.DebugLevel:
		color = ColorPurple
	case logrus.InfoLevel:
		color = ColorGreen
	case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel:
		color = ColorRed
		notify = true
	default:
		color = ColorYellow
		notify = true
	}

	_, err := hh.c.Room.Notification(hh.RoomName, &hipchat.NotificationRequest{
		From:          hh.Username,
		Message:       e.Message,
		MessageFormat: "text",
		Notify:        notify,
		Color:         color,
	})

	return err
}

func (hh *HiprusHook) initClient() error {
	c := hipchat.NewClient(hh.AuthToken)

	if hh.BaseURL != "" {
		hipchatUrl, _ := url.Parse(hh.BaseURL)
		c.BaseURL = hipchatUrl
	}

	hh.c = c

	if hh.Username == "" {
		hh.Username = "HipRus"
	}

	return nil
}
<|endoftext|>


<commit_before>package transform

import (
	"mater/vect"
	"math"
)

type Rotation struct {
	//sine and cosine.
	S, C float64
}

func (rot *Rotation) SetIdentity() {
	rot.S = 0
	rot.C = 1
}

func (rot *Rotation) SetAngle(angle float64) {
	rot.C = math.Cos(angle)
	rot.S = math.Sin(angle)
}

func (rot *Rotation) Angle() float64 {
	return math.Atan2(rot.S, rot.C)
}

func (rot *Rotation) RotateVect(v vect.Vect) vect.Vect {
	return vect.Vect {
		X: v.X * rot.C - v.Y * rot.S,
		Y: v.X * rot.S + v.Y * rot.C,
	}
}

type Transform struct {
	Position vect.Vect
	Rotation
}

func (xf *Transform) SetIdentity() {
	xf.Position = vect.Vect{}
	xf.Rotation.SetIdentity()
}

func (xf *Transform) Set(pos vect.Vect, rot float64) {
	xf.Position = pos
	xf.SetAngle(rot)
}
<commit_msg>added transform.TransformVect<commit_after>package transform

import (
	"mater/vect"
	"math"
)

type Rotation struct {
	//sine and cosine.
	S, C float64
}

func (rot *Rotation) SetIdentity() {
	rot.S = 0
	rot.C = 1
}

func (rot *Rotation) SetAngle(angle float64) {
	rot.C = math.Cos(angle)
	rot.S = math.Sin(angle)
}

func (rot *Rotation) Angle() float64 {
	return math.Atan2(rot.S, rot.C)
}

//rotates the input vector.
func (rot *Rotation) RotateVect(v vect.Vect) vect.Vect {
	return vect.Vect {
		X: v.X * rot.C - v.Y * rot.S,
		Y: v.X * rot.S + v.Y * rot.C,
	}
}

type Transform struct {
	Position vect.Vect
	Rotation
}

func (xf *Transform) SetIdentity() {
	xf.Position = vect.Vect{}
	xf.Rotation.SetIdentity()
}

func (xf *Transform) Set(pos vect.Vect, rot float64) {
	xf.Position = pos
	xf.SetAngle(rot)
}

//moves and roates the input vector.
func (xf *Transform) TransformVect(v vect.Vect) vect.Vect {
	return vect.Add(xf.Position, xf.RotateVect(v))
}<|endoftext|>