<commit_before>// +build !amd64

package narray

// These are the fallbacks that are used when not on AMD64 platform.

// divSlice divides two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func divSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] / b[i]
	}
}

// addSlice adds two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func addSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] + b[i]
	}
}

// mulSlice multiply two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func mulSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] * b[i]
	}
}

// minSlice returns lowest valus of two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func minSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		if a[i] < b[i] {
			out[i] = a[i]
		} else {
			out[i] = b[i]
		}
	}
}

// maxSlice return maximum of two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func maxSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		if a[i] > b[i] {
			out[i] = a[i]
		} else {
			out[i] = b[i]
		}
	}
}

// cdivSlice will return c / values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func cdivSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c / a[i]
	}
}

// cmulSlice will return c * values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func cmulSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c * a[i]
	}
}

// caddSlice will return c * values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func caddSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c + a[i]
	}
}

// addScaledSlice adds a scaled narray elementwise.
// y = y + a * x
// Assumptions the assembly can make:
// y != nil, a != nil
// len(x)  == len(y)
func addScaledSlice(y, x []float64, a float64) {
	for i, v := range x {
		y[i] += v * a
	}
}

// sqrtSlice will return math.Sqrt(values) of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func sqrtSlice(out, a []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = math.Sqrt(a[i])
	}
}

// minSliceElement will the smallest value of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) > 0
func minSliceElement(a []float64) float64 {
	min := a[0]
	for i := 1; i < len(a); i++ {
		if a[i] < min {
			min = a[i]
		}
	}
	return min
}

// maxSliceElement will the biggest value of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) > 0
func maxSliceElement(a []float64) float64 {
	max := a[0]
	for i := 1; i < len(a); i++ {
		if a[i] > max {
			max = a[i]
		}
	}
	return max
}

// sliceSum will return the sum of all elements of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) >= 0
func sliceSum(a []float64) float64 {
	sum := 0.0
	for _, v := range a {
		sum += v
	}
	return sum
}

// absSlice will return math.Abs(values) of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func absSliceGo(out, a []float64) {
	for i, v := range a {
		out[i] = math.Abs(v)
	}
}
<commit_msg>Fix missing import and typo in fallback library.<commit_after>// +build !amd64

package narray

import "math"

// These are the fallbacks that are used when not on AMD64 platform.

// divSlice divides two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func divSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] / b[i]
	}
}

// addSlice adds two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func addSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] + b[i]
	}
}

// mulSlice multiply two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func mulSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = a[i] * b[i]
	}
}

// minSlice returns lowest valus of two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func minSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		if a[i] < b[i] {
			out[i] = a[i]
		} else {
			out[i] = b[i]
		}
	}
}

// maxSlice return maximum of two slices
// Assumptions the assembly can make:
// out != nil, a != nil, b != nil
// len(out)  == len(a) == len(b)
func maxSlice(out, a, b []float64) {
	for i := 0; i < len(out); i++ {
		if a[i] > b[i] {
			out[i] = a[i]
		} else {
			out[i] = b[i]
		}
	}
}

// cdivSlice will return c / values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func cdivSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c / a[i]
	}
}

// cmulSlice will return c * values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func cmulSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c * a[i]
	}
}

// caddSlice will return c * values of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func caddSlice(out, a []float64, c float64) {
	for i := 0; i < len(out); i++ {
		out[i] = c + a[i]
	}
}

// addScaledSlice adds a scaled narray elementwise.
// y = y + a * x
// Assumptions the assembly can make:
// y != nil, a != nil
// len(x)  == len(y)
func addScaledSlice(y, x []float64, a float64) {
	for i, v := range x {
		y[i] += v * a
	}
}

// sqrtSlice will return math.Sqrt(values) of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func sqrtSlice(out, a []float64) {
	for i := 0; i < len(out); i++ {
		out[i] = math.Sqrt(a[i])
	}
}

// minSliceElement will the smallest value of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) > 0
func minSliceElement(a []float64) float64 {
	min := a[0]
	for i := 1; i < len(a); i++ {
		if a[i] < min {
			min = a[i]
		}
	}
	return min
}

// maxSliceElement will the biggest value of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) > 0
func maxSliceElement(a []float64) float64 {
	max := a[0]
	for i := 1; i < len(a); i++ {
		if a[i] > max {
			max = a[i]
		}
	}
	return max
}

// sliceSum will return the sum of all elements of the slice
// Assumptions the assembly can make:
// a != nil
// len(a) >= 0
func sliceSum(a []float64) float64 {
	sum := 0.0
	for _, v := range a {
		sum += v
	}
	return sum
}

// absSlice will return math.Abs(values) of the array
// Assumptions the assembly can make:
// out != nil, a != nil
// len(out)  == len(a)
func absSlice(out, a []float64) {
	for i, v := range a {
		out[i] = math.Abs(v)
	}
}
<|endoftext|>


<commit_before>// The gosym command prints symbols in Go source code.
// It supports the following commands:
//
// gosym short
//
// The short command reads lines from standard input
// in short or long format (see the list command) and
// prints them in short format:
// 	file-position name new-name
// The file-position field holds the location of the identifier.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The new-name field holds the desired new name for the identifier.
//
// gosym export
//
// The export command reads lines in short or long
// format from its standard input and capitalises the first letter
// of all symbols (thus making them available to external
// packages)
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym unexport
//
// The unexport command reads lines in short or long
// format from its standard input and uncapitalises the first letter
// of all symbols (thus making them unavailable to external
// packages).
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym rename [old new]...
//
// The rename command renames any symbol with the
// given old name to the given new name. The
// qualifier symbol's qualifier is ignored.
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new name.
//
// gosym used pkg...
//
// The used command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have references to them from any other package.
//
// gosym unused pkg...
//
// The unused command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have no references to them from any other package.
//
// gosym list [flags] [pkg...]
//
// The list command prints a line for each identifier
// used in the named packages. Each line printed has at least 6 space-separated fields
// in the following format:
// 	file-position referenced-file-position package referenced-package name type-kind
// This format is known as "long" format.
// If no packages are named, "." is used.
//
// The file-position field holds the location of the identifier.
// The referenced-file-position field holds the location of the
// definition of the identifier.
// The package field holds the path of the package containing the identifier.
// The referenced-package field holds the path of the package
// where the identifier is defined.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The type-kind field holds the type class of identifier (const,
// type, var or func), and ends with a "+" sign if this line
// marks the definition of the identifier.
//   -a=false: print internal and universe symbols too
//   -k="type,const,var,func": kinds of symbol types to include
//   -t=false: print symbol type
//   -v=false: print warnings about undefined symbols
//
// gosym write [pkg...]
//
// The gosym command reads lines in short format (see the
// "short" subcommand) from its standard input
// that represent changes to make, and changes any of the
// named packages accordingly - that is, the identifier
// at each line's file-position (and all uses of it) is changed to the new-name
// field.
//
// If no packages are named, "." is used. No files outside the named packages
// will be changed. The names of any changed files will
// be printed.
//
// As with gofix, writes are destructive - make sure your
// source files are backed up before using this command.
package main

import (
	"bufio"
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/sym"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// TODO allow changing of package identifiers too.

// CAVEATS:
// - map keys are not properly resolved.
// - no declaration for init
// - identifer in a type switch probably doesn't work properly.
// - type names embedded in structs or interfaces don't rename properly.
// - import to . is not supported.
// - test files are not dealt with properly.
// - can't change package identifiers
// - there's no way to give an error if renaming creates a
//	clash of symbols.
// - conditional compilation not supported

var verbose = flag.Bool("v", true, "print warning messages")

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [-v] command [flags] [args...]\n")
		printf("%s", `
Gosym manipulates symbols in Go source code.
Various sub-commands print, process or write symbols.
`)
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() == 0 {
		flag.Usage()
	}
	name := flag.Arg(0)
	if name == "help" {
		help()
		return
	}
	var c cmd
	var args []string
	for _, e := range cmds {
		if e.name == name {
			e.fset.Parse(flag.Args()[1:])
			c = e.c
			args = e.fset.Args()
			break
		}
	}
	if c == nil {
		flag.Usage()
	}
	if err := runCmd(c, args); err != nil {
		log.Printf("gosym %s: %v", name, err)
		os.Exit(1)
	}
}

func runCmd(c cmd, args []string) error {
	types.Panic = false
	initGoPath()
	ctxt := newContext()
	defer ctxt.stdout.Flush()
	return c.run(ctxt, args)
}

type cmd interface {
	run(*context, []string) error
}

type cmdEntry struct {
	name  string
	about string
	c     cmd
	fset  *flag.FlagSet
}

var cmds []cmdEntry

func register(name string, c cmd, fset *flag.FlagSet, about string) {
	if fset == nil {
		fset = flag.NewFlagSet("gosym "+name, flag.ExitOnError)
	}
	fset.Usage = func() {
		fmt.Fprint(os.Stderr, about)
		fset.PrintDefaults()
	}
	cmds = append(cmds, cmdEntry{
		name:  name,
		about: about,
		c:     c,
		fset:  fset,
	})
}

func help() {
	for i, e := range cmds {
		if i > 0 {
			fmt.Printf("\n")
		}
		e.fset.SetOutput(os.Stdout)
		fmt.Print(e.about)
		e.fset.PrintDefaults()
	}
}

type context struct {
	mu sync.Mutex
	*sym.Context
	pkgCache map[string]*ast.Package
	pkgDirs  map[string]string // map from directory to package name.
	stdout   *bufio.Writer
}

func newContext() *context {
	ctxt := &context{
		pkgDirs: make(map[string]string),
		stdout:  bufio.NewWriter(os.Stdout),
		Context: sym.NewContext(),
	}
	ctxt.Logf = func(pos token.Pos, f string, a ...interface{}) {
		if !*verbose {
			return
		}
		log.Printf("%v: %s", ctxt.position(pos), fmt.Sprintf(f, a...))
	}
	return ctxt
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

func (ctxt *context) positionToImportPath(p token.Position) string {
	if p.Filename == "" {
		panic("empty file name")
	}
	dir := filepath.Dir(p.Filename)
	if pkg, ok := ctxt.pkgDirs[dir]; ok {
		return pkg
	}
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	ctxt.pkgDirs[dir] = bpkg.ImportPath
	return bpkg.ImportPath
}

func (ctxt *context) printf(f string, a ...interface{}) {
	fmt.Fprintf(ctxt.stdout, f, a...)
}

func (ctxt *context) position(pos token.Pos) token.Position {
	return ctxt.FileSet.Position(pos)
}

var emptyFileSet = token.NewFileSet()

func pretty(n ast.Node) string {
	var b bytes.Buffer
	printer.Fprint(&b, emptyFileSet, n)
	return b.String()
}
<commit_msg>exp/cmd/gosym: fix comment<commit_after>// The gosym command manipulates symbols in Go source code.
// It supports the following commands:
//
// gosym short
//
// The short command reads lines from standard input
// in short or long format (see the list command) and
// prints them in short format:
// 	file-position name new-name
// The file-position field holds the location of the identifier.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The new-name field holds the desired new name for the identifier.
//
// gosym export
//
// The export command reads lines in short or long
// format from its standard input and capitalises the first letter
// of all symbols (thus making them available to external
// packages)
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym unexport
//
// The unexport command reads lines in short or long
// format from its standard input and uncapitalises the first letter
// of all symbols (thus making them unavailable to external
// packages).
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new capitalisation.
//
// gosym rename [old new]...
//
// The rename command renames any symbol with the
// given old name to the given new name. The
// qualifier symbol's qualifier is ignored.
//
// Note that this may cause clashes with other symbols
// that have already been defined with the new name.
//
// gosym used pkg...
//
// The used command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have references to them from any other package.
//
// gosym unused pkg...
//
// The unused command reads lines in long format from the standard input and
// prints (in long format) any definitions found in the named packages that
// have no references to them from any other package.
//
// gosym list [flags] [pkg...]
//
// The list command prints a line for each identifier
// used in the named packages. Each line printed has at least 6 space-separated fields
// in the following format:
// 	file-position referenced-file-position package referenced-package name type-kind
// This format is known as "long" format.
// If no packages are named, "." is used.
//
// The file-position field holds the location of the identifier.
// The referenced-file-position field holds the location of the
// definition of the identifier.
// The package field holds the path of the package containing the identifier.
// The referenced-package field holds the path of the package
// where the identifier is defined.
// The name field holds the name of the identifier (in X.Y format if
// it is defined as a member of another type X).
// The type-kind field holds the type class of identifier (const,
// type, var or func), and ends with a "+" sign if this line
// marks the definition of the identifier.
//   -a=false: print internal and universe symbols too
//   -k="type,const,var,func": kinds of symbol types to include
//   -t=false: print symbol type
//   -v=false: print warnings about undefined symbols
//
// gosym write [pkg...]
//
// The gosym command reads lines in short format (see the
// "short" subcommand) from its standard input
// that represent changes to make, and changes any of the
// named packages accordingly - that is, the identifier
// at each line's file-position (and all uses of it) is changed to the new-name
// field.
//
// If no packages are named, "." is used. No files outside the named packages
// will be changed. The names of any changed files will
// be printed.
//
// As with gofix, writes are destructive - make sure your
// source files are backed up before using this command.
package main

import (
	"bufio"
	"bytes"
	"code.google.com/p/rog-go/exp/go/ast"
	"code.google.com/p/rog-go/exp/go/printer"
	"code.google.com/p/rog-go/exp/go/sym"
	"code.google.com/p/rog-go/exp/go/token"
	"code.google.com/p/rog-go/exp/go/types"
	"flag"
	"fmt"
	"go/build"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// TODO allow changing of package identifiers too.

// CAVEATS:
// - map keys are not properly resolved.
// - no declaration for init
// - identifer in a type switch probably doesn't work properly.
// - type names embedded in structs or interfaces don't rename properly.
// - import to . is not supported.
// - test files are not dealt with properly.
// - can't change package identifiers
// - there's no way to give an error if renaming creates a
//	clash of symbols.
// - conditional compilation not supported

var verbose = flag.Bool("v", true, "print warning messages")

func main() {
	printf := func(f string, a ...interface{}) { fmt.Fprintf(os.Stderr, f, a...) }
	flag.Usage = func() {
		printf("usage: gosym [-v] command [flags] [args...]\n")
		printf("%s", `
Gosym manipulates symbols in Go source code.
Various sub-commands print, process or write symbols.
`)
		os.Exit(2)
	}
	flag.Parse()
	if flag.NArg() == 0 {
		flag.Usage()
	}
	name := flag.Arg(0)
	if name == "help" {
		help()
		return
	}
	var c cmd
	var args []string
	for _, e := range cmds {
		if e.name == name {
			e.fset.Parse(flag.Args()[1:])
			c = e.c
			args = e.fset.Args()
			break
		}
	}
	if c == nil {
		flag.Usage()
	}
	if err := runCmd(c, args); err != nil {
		log.Printf("gosym %s: %v", name, err)
		os.Exit(1)
	}
}

func runCmd(c cmd, args []string) error {
	types.Panic = false
	initGoPath()
	ctxt := newContext()
	defer ctxt.stdout.Flush()
	return c.run(ctxt, args)
}

type cmd interface {
	run(*context, []string) error
}

type cmdEntry struct {
	name  string
	about string
	c     cmd
	fset  *flag.FlagSet
}

var cmds []cmdEntry

func register(name string, c cmd, fset *flag.FlagSet, about string) {
	if fset == nil {
		fset = flag.NewFlagSet("gosym "+name, flag.ExitOnError)
	}
	fset.Usage = func() {
		fmt.Fprint(os.Stderr, about)
		fset.PrintDefaults()
	}
	cmds = append(cmds, cmdEntry{
		name:  name,
		about: about,
		c:     c,
		fset:  fset,
	})
}

func help() {
	for i, e := range cmds {
		if i > 0 {
			fmt.Printf("\n")
		}
		e.fset.SetOutput(os.Stdout)
		fmt.Print(e.about)
		e.fset.PrintDefaults()
	}
}

type context struct {
	mu sync.Mutex
	*sym.Context
	pkgCache map[string]*ast.Package
	pkgDirs  map[string]string // map from directory to package name.
	stdout   *bufio.Writer
}

func newContext() *context {
	ctxt := &context{
		pkgDirs: make(map[string]string),
		stdout:  bufio.NewWriter(os.Stdout),
		Context: sym.NewContext(),
	}
	ctxt.Logf = func(pos token.Pos, f string, a ...interface{}) {
		if !*verbose {
			return
		}
		log.Printf("%v: %s", ctxt.position(pos), fmt.Sprintf(f, a...))
	}
	return ctxt
}

func initGoPath() {
	// take GOPATH, set types.GoPath to it if it's not empty.
	p := os.Getenv("GOPATH")
	if p == "" {
		return
	}
	gopath := strings.Split(p, ":")
	for i, d := range gopath {
		gopath[i] = filepath.Join(d, "src")
	}
	r := os.Getenv("GOROOT")
	if r != "" {
		gopath = append(gopath, r+"/src/pkg")
	}
	types.GoPath = gopath
}

func (ctxt *context) positionToImportPath(p token.Position) string {
	if p.Filename == "" {
		panic("empty file name")
	}
	dir := filepath.Dir(p.Filename)
	if pkg, ok := ctxt.pkgDirs[dir]; ok {
		return pkg
	}
	bpkg, err := build.Import(".", dir, build.FindOnly)
	if err != nil {
		panic(fmt.Errorf("cannot reverse-map filename to package: %v", err))
	}
	ctxt.pkgDirs[dir] = bpkg.ImportPath
	return bpkg.ImportPath
}

func (ctxt *context) printf(f string, a ...interface{}) {
	fmt.Fprintf(ctxt.stdout, f, a...)
}

func (ctxt *context) position(pos token.Pos) token.Position {
	return ctxt.FileSet.Position(pos)
}

var emptyFileSet = token.NewFileSet()

func pretty(n ast.Node) string {
	var b bytes.Buffer
	printer.Fprint(&b, emptyFileSet, n)
	return b.String()
}
<|endoftext|>


<commit_before>package goblin

import (
	"fmt"
	"reflect"
	"strings"
)

type Assertion struct {
	src  interface{}
	fail func(interface{})
}

func objectsAreEqual(a, b interface{}) bool {
	if reflect.TypeOf(a) != reflect.TypeOf(b) {
		return false
	}

	if reflect.DeepEqual(a, b) {
		return true
	}

	if fmt.Sprintf("%#v", a) == fmt.Sprintf("%#v", b) {
		return true
	}

	return false
}

func formatMessages(messages ...string) string {
	if len(messages) > 0 {
		return ", " + strings.Join(messages, " ")
	}
	return ""
}

func (a *Assertion) Eql(dst interface{}) {
	a.Equal(dst)
}

func (a *Assertion) Equal(dst interface{}) {
	if !objectsAreEqual(a.src, dst) {
		a.fail(fmt.Sprintf("%#v %s %#v", a.src, "does not equal", dst))
	}
}

func (a *Assertion) IsTrue(messages ...string) {
	if !objectsAreEqual(a.src, true) {
		message := fmt.Sprintf("%v %s%s", a.src, "expected false to be truthy", formatMessages(messages...))
		a.fail(message)
	}
}

func (a *Assertion) IsFalse(messages ...string) {
	if !objectsAreEqual(a.src, false) {
		message := fmt.Sprintf("%v %s%s", a.src, "expected true to be falsey", formatMessages(messages...))
		a.fail(message)
	}
}
<commit_msg>Add type error message instead of just "not equal"<commit_after>package goblin

import (
	"fmt"
	"reflect"
	"strings"
)

type Assertion struct {
	src  interface{}
	fail func(interface{})
}

func formatMessages(messages ...string) string {
	if len(messages) > 0 {
		return ", " + strings.Join(messages, " ")
	}
	return ""
}

func (a *Assertion) Eql(dst interface{}) {
	a.Equal(dst)
}

func (a *Assertion) Equal(dst interface{}) {
	if e := a.equal(dst); e != nil {
		a.fail(e)
	}
}

func (a *Assertion) equal(dst interface{}) error {
	if at, dt := reflect.TypeOf(a.src), reflect.TypeOf(dst); at != dt {
		return fmt.Errorf("%s(%#v) does not equal %s(%#v)", at, a.src, dt, dst)
	}

	if reflect.DeepEqual(a.src, dst) {
		return nil
	}

	if fmt.Sprintf("%#v", a.src) == fmt.Sprintf("%#v", dst) {
		return nil
	}

	return fmt.Errorf("%#v does not equal %#v", a.src, dst)
}

func (a *Assertion) IsTrue(messages ...string) {
	if a.equal(true) != nil {
		message := fmt.Sprintf("%v %s%s", a.src, "expected false to be truthy", formatMessages(messages...))
		a.fail(message)
	}
}

func (a *Assertion) IsFalse(messages ...string) {
	if a.equal(false) != nil {
		message := fmt.Sprintf("%v %s%s", a.src, "expected true to be falsey", formatMessages(messages...))
		a.fail(message)
	}
}
<|endoftext|>


<commit_before>package worker

import (
	"errors"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/atc"
	"github.com/concourse/atc/dbng"
)

//go:generate counterfeiter . WorkerProvider

type WorkerProvider interface {
	RunningWorkers() ([]Worker, error)
	GetWorker(string) (Worker, bool, error)

	FindWorkerForContainer(
		logger lager.Logger,
		teamID int,
		handle string,
	) (Worker, bool, error)

	FindWorkerForResourceCheckContainer(
		logger lager.Logger,
		teamID int,
		resourceUser dbng.ResourceUser,
		resourceType string,
		resourceSource atc.Source,
		types atc.VersionedResourceTypes,
	) (Worker, bool, error)

	FindWorkerForBuildContainer(
		logger lager.Logger,
		teamID int,
		buildID int,
		planID atc.PlanID,
	) (Worker, bool, error)
}

var (
	ErrNoWorkers     = errors.New("no workers")
	ErrMissingWorker = errors.New("worker for container is missing")
)

type NoCompatibleWorkersError struct {
	Spec    WorkerSpec
	Workers []Worker
}

func (err NoCompatibleWorkersError) Error() string {
	availableWorkers := ""
	for _, worker := range err.Workers {
		availableWorkers += "\n  - " + worker.Description()
	}

	return fmt.Sprintf(
		"no workers satisfying: %s\n\navailable workers: %s",
		err.Spec.Description(),
		availableWorkers,
	)
}

type pool struct {
	provider WorkerProvider

	rand *rand.Rand
}

func NewPool(provider WorkerProvider) Client {
	return &pool{
		provider: provider,
		rand:     rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (pool *pool) RunningWorkers() ([]Worker, error) {
	return pool.provider.RunningWorkers()
}

func (pool *pool) GetWorker(workerName string) (Worker, error) {
	worker, found, err := pool.provider.GetWorker(workerName)
	if err != nil {
		return nil, err
	}

	if !found {
		return nil, ErrNoWorkers
	}

	return worker, nil
}

func (pool *pool) AllSatisfying(spec WorkerSpec, resourceTypes atc.VersionedResourceTypes) ([]Worker, error) {
	workers, err := pool.provider.RunningWorkers()
	if err != nil {
		return nil, err
	}

	if len(workers) == 0 {
		return nil, ErrNoWorkers
	}

	compatibleTeamWorkers := []Worker{}
	compatibleGeneralWorkers := []Worker{}
	for _, worker := range workers {
		satisfyingWorker, err := worker.Satisfying(spec, resourceTypes)
		if err == nil {
			if worker.IsOwnedByTeam() {
				compatibleTeamWorkers = append(compatibleTeamWorkers, satisfyingWorker)
			} else {
				compatibleGeneralWorkers = append(compatibleGeneralWorkers, satisfyingWorker)
			}
		}
	}

	if len(compatibleTeamWorkers) != 0 {
		return compatibleTeamWorkers, nil
	}

	if len(compatibleGeneralWorkers) != 0 {
		return compatibleGeneralWorkers, nil
	}

	return nil, NoCompatibleWorkersError{
		Spec:    spec,
		Workers: workers,
	}
}

func (pool *pool) Satisfying(spec WorkerSpec, resourceTypes atc.VersionedResourceTypes) (Worker, error) {
	compatibleWorkers, err := pool.AllSatisfying(spec, resourceTypes)
	if err != nil {
		return nil, err
	}
	randomWorker := compatibleWorkers[pool.rand.Intn(len(compatibleWorkers))]
	return randomWorker, nil
}

func (pool *pool) FindOrCreateBuildContainer(
	logger lager.Logger,
	signals <-chan os.Signal,
	delegate ImageFetchingDelegate,
	buildID int,
	planID atc.PlanID,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
) (Container, error) {
	worker, found, err := pool.provider.FindWorkerForBuildContainer(
		logger.Session("find-worker"),
		spec.TeamID, // XXX: better place for this?
		buildID,
		planID,
	)
	if err != nil {
		return nil, err
	}

	if !found {
		compatibleWorkers, err := pool.AllSatisfying(spec.WorkerSpec(), resourceTypes)
		if err != nil {
			return nil, err
		}

		workersByCount := map[int][]Worker{}
		var highestCount int
		for _, w := range compatibleWorkers {
			candidateInputCount := 0

			for _, inputSource := range spec.Inputs {
				_, found, err := inputSource.Source().VolumeOn(w)
				if err != nil {
					return nil, err
				}

				if found {
					candidateInputCount++
				}
			}

			workersByCount[candidateInputCount] = append(workersByCount[candidateInputCount], w)

			if candidateInputCount >= highestCount {
				highestCount = candidateInputCount
			}
		}

		workers := workersByCount[highestCount]

		worker = workers[rand.Intn(len(workers))]
	}

	return worker.FindOrCreateBuildContainer(
		logger,
		signals,
		delegate,
		buildID,
		planID,
		metadata,
		spec,
		resourceTypes,
	)
}

func (pool *pool) CreateResourceGetContainer(
	logger lager.Logger,
	resourceUser dbng.ResourceUser,
	cancel <-chan os.Signal,
	delegate ImageFetchingDelegate,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	resourceType string,
	version atc.Version,
	source atc.Source,
	params atc.Params,
) (Container, error) {
	worker, err := pool.Satisfying(spec.WorkerSpec(), resourceTypes)
	if err != nil {
		return nil, err
	}

	return worker.CreateResourceGetContainer(
		logger,
		resourceUser,
		cancel,
		delegate,
		metadata,
		spec,
		resourceTypes,
		resourceType,
		version,
		source,
		params,
	)
}

func (pool *pool) FindOrCreateResourceCheckContainer(
	logger lager.Logger,
	resourceUser dbng.ResourceUser,
	cancel <-chan os.Signal,
	delegate ImageFetchingDelegate,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	resourceType string,
	source atc.Source,
) (Container, error) {
	worker, found, err := pool.provider.FindWorkerForResourceCheckContainer(
		logger.Session("find-worker"),
		spec.TeamID, // XXX: better place for this?
		resourceUser,
		resourceType,
		source,
		resourceTypes,
	)
	if err != nil {
		return nil, err
	}

	if !found {
		worker, err = pool.Satisfying(spec.WorkerSpec(), resourceTypes)
		if err != nil {
			return nil, err
		}
	}

	return worker.FindOrCreateResourceCheckContainer(
		logger,
		resourceUser,
		cancel,
		delegate,
		metadata,
		spec,
		resourceTypes,
		resourceType,
		source,
	)
}

func (pool *pool) FindContainerByHandle(logger lager.Logger, teamID int, handle string) (Container, bool, error) {
	worker, found, err := pool.provider.FindWorkerForContainer(
		logger.Session("find-worker"),
		teamID,
		handle,
	)
	if err != nil {
		return nil, false, err
	}

	if !found {
		return nil, false, nil
	}

	return worker.FindContainerByHandle(logger, teamID, handle)
}

func (*pool) FindResourceTypeByPath(string) (atc.WorkerResourceType, bool) {
	return atc.WorkerResourceType{}, false
}

func (*pool) CreateVolumeForResourceCache(lager.Logger, VolumeSpec, *dbng.UsedResourceCache) (Volume, error) {
	return nil, errors.New("CreateVolumeForResourceCache not implemented for pool")
}

func (*pool) FindInitializedVolumeForResourceCache(logger lager.Logger, resourceCache *dbng.UsedResourceCache) (Volume, bool, error) {
	return nil, false, errors.New("FindInitializedVolumeForResourceCache not implemented for pool")
}

func (*pool) LookupVolume(lager.Logger, string) (Volume, bool, error) {
	return nil, false, errors.New("LookupVolume not implemented for pool")
}

func (pool *pool) findCompatibleWorker(
	containerSpec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	sources map[string]ArtifactSource,
) (Worker, []VolumeMount, []string, error) {
	compatibleWorkers, err := pool.AllSatisfying(containerSpec.WorkerSpec(), resourceTypes)
	if err != nil {
		return nil, nil, nil, err
	}

	// find the worker with the most volumes
	mounts := []VolumeMount{}
	missingSources := []string{}
	var chosenWorker Worker

	// for each worker that matches tags, platform, etc -- what is the etc?
	for _, w := range compatibleWorkers {
		candidateMounts := []VolumeMount{}
		missing := []string{}

		for name, source := range sources {
			// look at all the inputs/outputs we're looking for
			ourVolume, found, err := source.VolumeOn(w)
			if err != nil {
				return nil, nil, nil, err
			}

			if found {
				candidateMounts = append(candidateMounts, VolumeMount{
					Volume:    ourVolume,
					MountPath: resourcesDir("put/" + name),
				})
			} else {
				missing = append(missing, name)
			}
		}

		if len(candidateMounts) >= len(mounts) {
			mounts = candidateMounts
			missingSources = missing
			chosenWorker = w
		}
	}

	return chosenWorker, mounts, missingSources, nil
}

func resourcesDir(suffix string) string {
	return filepath.Join("/tmp", "build", suffix)
}
<commit_msg>use pool.rand<commit_after>package worker

import (
	"errors"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"time"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/atc"
	"github.com/concourse/atc/dbng"
)

//go:generate counterfeiter . WorkerProvider

type WorkerProvider interface {
	RunningWorkers() ([]Worker, error)
	GetWorker(string) (Worker, bool, error)

	FindWorkerForContainer(
		logger lager.Logger,
		teamID int,
		handle string,
	) (Worker, bool, error)

	FindWorkerForResourceCheckContainer(
		logger lager.Logger,
		teamID int,
		resourceUser dbng.ResourceUser,
		resourceType string,
		resourceSource atc.Source,
		types atc.VersionedResourceTypes,
	) (Worker, bool, error)

	FindWorkerForBuildContainer(
		logger lager.Logger,
		teamID int,
		buildID int,
		planID atc.PlanID,
	) (Worker, bool, error)
}

var (
	ErrNoWorkers     = errors.New("no workers")
	ErrMissingWorker = errors.New("worker for container is missing")
)

type NoCompatibleWorkersError struct {
	Spec    WorkerSpec
	Workers []Worker
}

func (err NoCompatibleWorkersError) Error() string {
	availableWorkers := ""
	for _, worker := range err.Workers {
		availableWorkers += "\n  - " + worker.Description()
	}

	return fmt.Sprintf(
		"no workers satisfying: %s\n\navailable workers: %s",
		err.Spec.Description(),
		availableWorkers,
	)
}

type pool struct {
	provider WorkerProvider

	rand *rand.Rand
}

func NewPool(provider WorkerProvider) Client {
	return &pool{
		provider: provider,
		rand:     rand.New(rand.NewSource(time.Now().UnixNano())),
	}
}

func (pool *pool) RunningWorkers() ([]Worker, error) {
	return pool.provider.RunningWorkers()
}

func (pool *pool) GetWorker(workerName string) (Worker, error) {
	worker, found, err := pool.provider.GetWorker(workerName)
	if err != nil {
		return nil, err
	}

	if !found {
		return nil, ErrNoWorkers
	}

	return worker, nil
}

func (pool *pool) AllSatisfying(spec WorkerSpec, resourceTypes atc.VersionedResourceTypes) ([]Worker, error) {
	workers, err := pool.provider.RunningWorkers()
	if err != nil {
		return nil, err
	}

	if len(workers) == 0 {
		return nil, ErrNoWorkers
	}

	compatibleTeamWorkers := []Worker{}
	compatibleGeneralWorkers := []Worker{}
	for _, worker := range workers {
		satisfyingWorker, err := worker.Satisfying(spec, resourceTypes)
		if err == nil {
			if worker.IsOwnedByTeam() {
				compatibleTeamWorkers = append(compatibleTeamWorkers, satisfyingWorker)
			} else {
				compatibleGeneralWorkers = append(compatibleGeneralWorkers, satisfyingWorker)
			}
		}
	}

	if len(compatibleTeamWorkers) != 0 {
		return compatibleTeamWorkers, nil
	}

	if len(compatibleGeneralWorkers) != 0 {
		return compatibleGeneralWorkers, nil
	}

	return nil, NoCompatibleWorkersError{
		Spec:    spec,
		Workers: workers,
	}
}

func (pool *pool) Satisfying(spec WorkerSpec, resourceTypes atc.VersionedResourceTypes) (Worker, error) {
	compatibleWorkers, err := pool.AllSatisfying(spec, resourceTypes)
	if err != nil {
		return nil, err
	}
	randomWorker := compatibleWorkers[pool.rand.Intn(len(compatibleWorkers))]
	return randomWorker, nil
}

func (pool *pool) FindOrCreateBuildContainer(
	logger lager.Logger,
	signals <-chan os.Signal,
	delegate ImageFetchingDelegate,
	buildID int,
	planID atc.PlanID,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
) (Container, error) {
	worker, found, err := pool.provider.FindWorkerForBuildContainer(
		logger.Session("find-worker"),
		spec.TeamID, // XXX: better place for this?
		buildID,
		planID,
	)
	if err != nil {
		return nil, err
	}

	if !found {
		compatibleWorkers, err := pool.AllSatisfying(spec.WorkerSpec(), resourceTypes)
		if err != nil {
			return nil, err
		}

		workersByCount := map[int][]Worker{}
		var highestCount int
		for _, w := range compatibleWorkers {
			candidateInputCount := 0

			for _, inputSource := range spec.Inputs {
				_, found, err := inputSource.Source().VolumeOn(w)
				if err != nil {
					return nil, err
				}

				if found {
					candidateInputCount++
				}
			}

			workersByCount[candidateInputCount] = append(workersByCount[candidateInputCount], w)

			if candidateInputCount >= highestCount {
				highestCount = candidateInputCount
			}
		}

		workers := workersByCount[highestCount]

		worker = workers[pool.rand.Intn(len(workers))]
	}

	return worker.FindOrCreateBuildContainer(
		logger,
		signals,
		delegate,
		buildID,
		planID,
		metadata,
		spec,
		resourceTypes,
	)
}

func (pool *pool) CreateResourceGetContainer(
	logger lager.Logger,
	resourceUser dbng.ResourceUser,
	cancel <-chan os.Signal,
	delegate ImageFetchingDelegate,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	resourceType string,
	version atc.Version,
	source atc.Source,
	params atc.Params,
) (Container, error) {
	worker, err := pool.Satisfying(spec.WorkerSpec(), resourceTypes)
	if err != nil {
		return nil, err
	}

	return worker.CreateResourceGetContainer(
		logger,
		resourceUser,
		cancel,
		delegate,
		metadata,
		spec,
		resourceTypes,
		resourceType,
		version,
		source,
		params,
	)
}

func (pool *pool) FindOrCreateResourceCheckContainer(
	logger lager.Logger,
	resourceUser dbng.ResourceUser,
	cancel <-chan os.Signal,
	delegate ImageFetchingDelegate,
	metadata dbng.ContainerMetadata,
	spec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	resourceType string,
	source atc.Source,
) (Container, error) {
	worker, found, err := pool.provider.FindWorkerForResourceCheckContainer(
		logger.Session("find-worker"),
		spec.TeamID, // XXX: better place for this?
		resourceUser,
		resourceType,
		source,
		resourceTypes,
	)
	if err != nil {
		return nil, err
	}

	if !found {
		worker, err = pool.Satisfying(spec.WorkerSpec(), resourceTypes)
		if err != nil {
			return nil, err
		}
	}

	return worker.FindOrCreateResourceCheckContainer(
		logger,
		resourceUser,
		cancel,
		delegate,
		metadata,
		spec,
		resourceTypes,
		resourceType,
		source,
	)
}

func (pool *pool) FindContainerByHandle(logger lager.Logger, teamID int, handle string) (Container, bool, error) {
	worker, found, err := pool.provider.FindWorkerForContainer(
		logger.Session("find-worker"),
		teamID,
		handle,
	)
	if err != nil {
		return nil, false, err
	}

	if !found {
		return nil, false, nil
	}

	return worker.FindContainerByHandle(logger, teamID, handle)
}

func (*pool) FindResourceTypeByPath(string) (atc.WorkerResourceType, bool) {
	return atc.WorkerResourceType{}, false
}

func (*pool) CreateVolumeForResourceCache(lager.Logger, VolumeSpec, *dbng.UsedResourceCache) (Volume, error) {
	return nil, errors.New("CreateVolumeForResourceCache not implemented for pool")
}

func (*pool) FindInitializedVolumeForResourceCache(logger lager.Logger, resourceCache *dbng.UsedResourceCache) (Volume, bool, error) {
	return nil, false, errors.New("FindInitializedVolumeForResourceCache not implemented for pool")
}

func (*pool) LookupVolume(lager.Logger, string) (Volume, bool, error) {
	return nil, false, errors.New("LookupVolume not implemented for pool")
}

func (pool *pool) findCompatibleWorker(
	containerSpec ContainerSpec,
	resourceTypes atc.VersionedResourceTypes,
	sources map[string]ArtifactSource,
) (Worker, []VolumeMount, []string, error) {
	compatibleWorkers, err := pool.AllSatisfying(containerSpec.WorkerSpec(), resourceTypes)
	if err != nil {
		return nil, nil, nil, err
	}

	// find the worker with the most volumes
	mounts := []VolumeMount{}
	missingSources := []string{}
	var chosenWorker Worker

	// for each worker that matches tags, platform, etc -- what is the etc?
	for _, w := range compatibleWorkers {
		candidateMounts := []VolumeMount{}
		missing := []string{}

		for name, source := range sources {
			// look at all the inputs/outputs we're looking for
			ourVolume, found, err := source.VolumeOn(w)
			if err != nil {
				return nil, nil, nil, err
			}

			if found {
				candidateMounts = append(candidateMounts, VolumeMount{
					Volume:    ourVolume,
					MountPath: resourcesDir("put/" + name),
				})
			} else {
				missing = append(missing, name)
			}
		}

		if len(candidateMounts) >= len(mounts) {
			mounts = candidateMounts
			missingSources = missing
			chosenWorker = w
		}
	}

	return chosenWorker, mounts, missingSources, nil
}

func resourcesDir(suffix string) string {
	return filepath.Join("/tmp", "build", suffix)
}
<|endoftext|>


<commit_before>package esatompub

import (
	"database/sql"
	"github.com/xtracdev/goes"
	"time"
)

type TimestampedEvent struct {
	goes.Event
	Timestamp time.Time
}

const (
	sqlSelectRecent       = `select event_time, aggregate_id, version, typecode, payload from atom_event where feedid is null`
	sqlSelectForFeed      = `select event_time, aggregate_id, version, typecode, payload from atom_event where feedid = :1`
	sqlSelectPreviousFeed = `select previous from feed where feedid = :1`
	sqlSelectNextFeed     = `select feedid from feed where previous = :1`
	sqlSelectEvent        = `select event_time, typecode, payload from atom_event where aggregate_id = :1 and version = :2`
)

func RetrieveRecent(db *sql.DB) ([]TimestampedEvent, error) {
	return retrieveEvents(db, sqlSelectRecent, "")
}

func RetrieveArchive(db *sql.DB, feedid string) ([]TimestampedEvent, error) {
	return retrieveEvents(db, sqlSelectForFeed, feedid)
}

func retrieveEvents(db *sql.DB, query string, feedid string) ([]TimestampedEvent, error) {
	var events []TimestampedEvent

	var rows *sql.Rows
	var err error
	if feedid == "" {
		rows, err = db.Query(query)
	} else {
		rows, err = db.Query(query, feedid)
	}

	if err != nil {
		return events, err
	}

	defer rows.Close()

	var eventTime time.Time
	var aggregateId, typecode string
	var version int
	var payload []byte

	for rows.Next() {
		err := rows.Scan(&eventTime, &aggregateId, &version, &typecode, &payload)
		if err != nil {
			return events, err
		}

		event := TimestampedEvent{
			Event: goes.Event{
				Source:   aggregateId,
				Version:  version,
				Payload:  payload,
				TypeCode: typecode,
			},
			Timestamp: eventTime,
		}

		events = append(events, event)
	}

	if err = rows.Err(); err != nil {
		return events, err
	}

	return events, nil
}

func RetrieveLastFeed(db *sql.DB) (string, error) {
	var feedid string

	err := db.QueryRow(sqlLatestFeedId).Scan(&feedid)
	if err == sql.ErrNoRows {
		return "", nil
	} else if err != nil {
		return "", err
	}

	return feedid, nil
}

func RetrievePreviousFeed(db *sql.DB, id string) (sql.NullString, error) {
	var feedid sql.NullString

	err := db.QueryRow(sqlSelectPreviousFeed, id).Scan(&feedid)
	if err == sql.ErrNoRows {
		return feedid, nil
	} else if err != nil {
		return feedid, err
	}

	return feedid, nil
}

func RetrieveNextFeed(db *sql.DB, feedId string) (sql.NullString, error) {
	var previous sql.NullString

	err := db.QueryRow(sqlSelectNextFeed, feedId).Scan(&previous)
	if err == sql.ErrNoRows {
		return previous, nil
	} else if err != nil {
		return previous, err
	}

	return previous, nil
}

func RetrieveEvent(db *sql.DB, aggID string, version int) (TimestampedEvent, error) {
	var event TimestampedEvent

	var eventTime time.Time
	var typecode string
	var payload []byte

	err := db.QueryRow(sqlSelectEvent, aggID, version).Scan(&eventTime, &typecode, &payload)
	if err != nil {
		return event, err //Caller can sort out no rows vs other error
	}

	event = TimestampedEvent{
		Event: goes.Event{
			Source:   aggID,
			Version:  version,
			Payload:  payload,
			TypeCode: typecode,
		},
		Timestamp: eventTime,
	}

	return event, nil
}
<commit_msg>Added order for feed data<commit_after>package esatompub

import (
	"database/sql"
	"github.com/xtracdev/goes"
	"time"
)

type TimestampedEvent struct {
	goes.Event
	Timestamp time.Time
}

const (
	sqlSelectRecent       = `select event_time, aggregate_id, version, typecode, payload from atom_event where feedid is null order by id desc`
	sqlSelectForFeed      = `select event_time, aggregate_id, version, typecode, payload from atom_event where feedid = :1 order by id desc`
	sqlSelectPreviousFeed = `select previous from feed where feedid = :1`
	sqlSelectNextFeed     = `select feedid from feed where previous = :1`
	sqlSelectEvent        = `select event_time, typecode, payload from atom_event where aggregate_id = :1 and version = :2`
)

func RetrieveRecent(db *sql.DB) ([]TimestampedEvent, error) {
	return retrieveEvents(db, sqlSelectRecent, "")
}

func RetrieveArchive(db *sql.DB, feedid string) ([]TimestampedEvent, error) {
	return retrieveEvents(db, sqlSelectForFeed, feedid)
}

func retrieveEvents(db *sql.DB, query string, feedid string) ([]TimestampedEvent, error) {
	var events []TimestampedEvent

	var rows *sql.Rows
	var err error
	if feedid == "" {
		rows, err = db.Query(query)
	} else {
		rows, err = db.Query(query, feedid)
	}

	if err != nil {
		return events, err
	}

	defer rows.Close()

	var eventTime time.Time
	var aggregateId, typecode string
	var version int
	var payload []byte

	for rows.Next() {
		err := rows.Scan(&eventTime, &aggregateId, &version, &typecode, &payload)
		if err != nil {
			return events, err
		}

		event := TimestampedEvent{
			Event: goes.Event{
				Source:   aggregateId,
				Version:  version,
				Payload:  payload,
				TypeCode: typecode,
			},
			Timestamp: eventTime,
		}

		events = append(events, event)
	}

	if err = rows.Err(); err != nil {
		return events, err
	}

	return events, nil
}

func RetrieveLastFeed(db *sql.DB) (string, error) {
	var feedid string

	err := db.QueryRow(sqlLatestFeedId).Scan(&feedid)
	if err == sql.ErrNoRows {
		return "", nil
	} else if err != nil {
		return "", err
	}

	return feedid, nil
}

func RetrievePreviousFeed(db *sql.DB, id string) (sql.NullString, error) {
	var feedid sql.NullString

	err := db.QueryRow(sqlSelectPreviousFeed, id).Scan(&feedid)
	if err == sql.ErrNoRows {
		return feedid, nil
	} else if err != nil {
		return feedid, err
	}

	return feedid, nil
}

func RetrieveNextFeed(db *sql.DB, feedId string) (sql.NullString, error) {
	var previous sql.NullString

	err := db.QueryRow(sqlSelectNextFeed, feedId).Scan(&previous)
	if err == sql.ErrNoRows {
		return previous, nil
	} else if err != nil {
		return previous, err
	}

	return previous, nil
}

func RetrieveEvent(db *sql.DB, aggID string, version int) (TimestampedEvent, error) {
	var event TimestampedEvent

	var eventTime time.Time
	var typecode string
	var payload []byte

	err := db.QueryRow(sqlSelectEvent, aggID, version).Scan(&eventTime, &typecode, &payload)
	if err != nil {
		return event, err //Caller can sort out no rows vs other error
	}

	event = TimestampedEvent{
		Event: goes.Event{
			Source:   aggID,
			Version:  version,
			Payload:  payload,
			TypeCode: typecode,
		},
		Timestamp: eventTime,
	}

	return event, nil
}
<|endoftext|>


<commit_before>package drivers

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"os"
	"strings"
)

const (
	NfsOptions   = "nfsopts"
	DefaultNfsV3 = "port=2049,nolock,proto=tcp"
)

type nfsDriver struct {
	volumeDriver
	version int
	nfsopts map[string]string
}

var (
	EmptyMap = map[string]string{}
)

func NewNFSDriver(root string, version int, nfsopts string) nfsDriver {
	d := nfsDriver{
		volumeDriver: newVolumeDriver(root),
		version:      version,
		nfsopts:      map[string]string{},
	}

	if len(nfsopts) > 0 {
		d.nfsopts[NfsOptions] = nfsopts
	}
	return d
}

func (n nfsDriver) Mount(r volume.Request) volume.Response {
	log.Debugf("Entering Mount: %v", r)
	n.m.Lock()
	defer n.m.Unlock()
	hostdir := mountpoint(n.root, r.Name)
	source := n.fixSource(r)

	if n.mountm.HasMount(r.Name) && n.mountm.Count(r.Name) > 0 {
		log.Infof("Using existing NFS volume mount: %s", hostdir)
		n.mountm.Increment(r.Name)
		return volume.Response{Mountpoint: hostdir}
	}

	log.Infof("Mounting NFS volume %s on %s", source, hostdir)

	if err := createDest(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	if err := n.mountVolume(source, hostdir, n.version); err != nil {
		return volume.Response{Err: err.Error()}
	}
	n.mountm.Add(r.Name, hostdir)
	return volume.Response{Mountpoint: hostdir}
}

func (n nfsDriver) Unmount(r volume.Request) volume.Response {
	log.Debugf("Entering Unmount: %v", r)

	n.m.Lock()
	defer n.m.Unlock()
	hostdir := mountpoint(n.root, r.Name)

	if n.mountm.HasMount(r.Name) {
		if n.mountm.Count(r.Name) > 1 {
			log.Printf("Skipping unmount for %s - in use by other containers", r.Name)
			n.mountm.Decrement(r.Name)
			return volume.Response{}
		}
		n.mountm.Decrement(r.Name)
	}

	log.Infof("Unmounting volume name %s from %s", r.Name, hostdir)

	if err := run(fmt.Sprintf("umount %s", hostdir)); err != nil {
		return volume.Response{Err: err.Error()}
	}

	n.mountm.DeleteIfNotManaged(r.Name)

	if err := os.RemoveAll(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	return volume.Response{}
}

func (n nfsDriver) fixSource(r volume.Request) string {
	if n.mountm.HasOption(r.Name, ShareOpt) {
		return n.mountm.GetOption(r.Name, ShareOpt)
	}
	source := strings.Split(r.Name, "/")
	source[0] = source[0] + ":"
	return strings.Join(source, "/")
}

func (n nfsDriver) mountVolume(source, dest string, version int) error {
	var cmd string

	options := merge(n.mountm.GetOptions(dest), n.nfsopts)
	opts := ""
	if val, ok := options[NfsOptions]; ok {
		opts = val
	}

	mountCmd := "mount"

	if log.GetLevel() == log.DebugLevel {
		mountCmd = mountCmd + " -v"
	}

	switch version {
	case 3:
		log.Debugf("Mounting with NFSv3 - src: %s, dest: %s", source, dest)
		if len(opts) < 1 {
			opts = DefaultNfsV3
		}
	default:
		log.Debugf("Mounting with NFSv4 - src: %s, dest: %s", source, dest)
		if len(opts) > 0 {
			cmd = fmt.Sprintf("%s -t nfs4 -o %s %s %s", mountCmd, opts, source, dest)
		} else {
			cmd = fmt.Sprintf("%s -t nfs4 %s %s", mountCmd, source, dest)
		}
	}
	log.Debugf("exec: %s\n", cmd)
	return run(cmd)
}
<commit_msg>nfsv3 mount fix<commit_after>package drivers

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"os"
	"strings"
)

const (
	NfsOptions   = "nfsopts"
	DefaultNfsV3 = "port=2049,nolock,proto=tcp"
)

type nfsDriver struct {
	volumeDriver
	version int
	nfsopts map[string]string
}

var (
	EmptyMap = map[string]string{}
)

func NewNFSDriver(root string, version int, nfsopts string) nfsDriver {
	d := nfsDriver{
		volumeDriver: newVolumeDriver(root),
		version:      version,
		nfsopts:      map[string]string{},
	}

	if len(nfsopts) > 0 {
		d.nfsopts[NfsOptions] = nfsopts
	}
	return d
}

func (n nfsDriver) Mount(r volume.Request) volume.Response {
	log.Debugf("Entering Mount: %v", r)
	n.m.Lock()
	defer n.m.Unlock()
	hostdir := mountpoint(n.root, r.Name)
	source := n.fixSource(r)

	if n.mountm.HasMount(r.Name) && n.mountm.Count(r.Name) > 0 {
		log.Infof("Using existing NFS volume mount: %s", hostdir)
		n.mountm.Increment(r.Name)
		return volume.Response{Mountpoint: hostdir}
	}

	log.Infof("Mounting NFS volume %s on %s", source, hostdir)

	if err := createDest(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	if err := n.mountVolume(source, hostdir, n.version); err != nil {
		return volume.Response{Err: err.Error()}
	}
	n.mountm.Add(r.Name, hostdir)
	return volume.Response{Mountpoint: hostdir}
}

func (n nfsDriver) Unmount(r volume.Request) volume.Response {
	log.Debugf("Entering Unmount: %v", r)

	n.m.Lock()
	defer n.m.Unlock()
	hostdir := mountpoint(n.root, r.Name)

	if n.mountm.HasMount(r.Name) {
		if n.mountm.Count(r.Name) > 1 {
			log.Printf("Skipping unmount for %s - in use by other containers", r.Name)
			n.mountm.Decrement(r.Name)
			return volume.Response{}
		}
		n.mountm.Decrement(r.Name)
	}

	log.Infof("Unmounting volume name %s from %s", r.Name, hostdir)

	if err := run(fmt.Sprintf("umount %s", hostdir)); err != nil {
		return volume.Response{Err: err.Error()}
	}

	n.mountm.DeleteIfNotManaged(r.Name)

	if err := os.RemoveAll(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	return volume.Response{}
}

func (n nfsDriver) fixSource(r volume.Request) string {
	if n.mountm.HasOption(r.Name, ShareOpt) {
		return n.mountm.GetOption(r.Name, ShareOpt)
	}
	source := strings.Split(r.Name, "/")
	source[0] = source[0] + ":"
	return strings.Join(source, "/")
}

func (n nfsDriver) mountVolume(source, dest string, version int) error {
	var cmd string

	options := merge(n.mountm.GetOptions(dest), n.nfsopts)
	opts := ""
	if val, ok := options[NfsOptions]; ok {
		opts = val
	}

	mountCmd := "mount"

	if log.GetLevel() == log.DebugLevel {
		mountCmd = mountCmd + " -v"
	}

	switch version {
	case 3:
		log.Debugf("Mounting with NFSv3 - src: %s, dest: %s", source, dest)
		if len(opts) < 1 {
			opts = DefaultNfsV3
		}
		cmd = fmt.Sprintf("%s -t nfs -o %s %s %s", mountCmd, opts, source, dest)
	default:
		log.Debugf("Mounting with NFSv4 - src: %s, dest: %s", source, dest)
		if len(opts) > 0 {
			cmd = fmt.Sprintf("%s -t nfs4 -o %s %s %s", mountCmd, opts, source, dest)
		} else {
			cmd = fmt.Sprintf("%s -t nfs4 %s %s", mountCmd, source, dest)
		}
	}
	log.Debugf("exec: %s\n", cmd)
	return run(cmd)
}
<|endoftext|>


<commit_before>package gorocksdb

// #include "rocksdb/c.h"
import "C"
import (
	"errors"
	"io"
)

// WriteBatch is a batching of Puts, Merges and Deletes.
type WriteBatch struct {
	c *C.rocksdb_writebatch_t
}

// NewWriteBatch create a WriteBatch object.
func NewWriteBatch() *WriteBatch {
	return NewNativeWriteBatch(C.rocksdb_writebatch_create())
}

// NewNativeWriteBatch create a WriteBatch object.
func NewNativeWriteBatch(c *C.rocksdb_writebatch_t) *WriteBatch {
	return &WriteBatch{c}
}

// WriteBatchFrom creates a write batch from a serialized WriteBatch.
func WriteBatchFrom(data []byte) *WriteBatch {
	return NewNativeWriteBatch(C.rocksdb_writebatch_create_from(byteToChar(data), C.size_t(len(data))))
}

// Put queues a key-value pair.
func (wb *WriteBatch) Put(key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_put(wb.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// PutCF queues a key-value pair in a column family.
func (wb *WriteBatch) PutCF(cf *ColumnFamilyHandle, key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_put_cf(wb.c, cf.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// Merge queues a merge of "value" with the existing value of "key".
func (wb *WriteBatch) Merge(key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_merge(wb.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// MergeCF queues a merge of "value" with the existing value of "key" in a
// column family.
func (wb *WriteBatch) MergeCF(cf *ColumnFamilyHandle, key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_merge_cf(wb.c, cf.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// Delete queues a deletion of the data at key.
func (wb *WriteBatch) Delete(key []byte) {
	cKey := byteToChar(key)
	C.rocksdb_writebatch_delete(wb.c, cKey, C.size_t(len(key)))
}

// DeleteCF queues a deletion of the data at key in a column family.
func (wb *WriteBatch) DeleteCF(cf *ColumnFamilyHandle, key []byte) {
	cKey := byteToChar(key)
	C.rocksdb_writebatch_delete_cf(wb.c, cf.c, cKey, C.size_t(len(key)))
}

// Data returns the serialized version of this batch.
func (wb *WriteBatch) Data() []byte {
	var cSize C.size_t
	cValue := C.rocksdb_writebatch_data(wb.c, &cSize)
	return charToByte(cValue, cSize)
}

// Count returns the number of updates in the batch.
func (wb *WriteBatch) Count() int {
	return int(C.rocksdb_writebatch_count(wb.c))
}

// NewIterator returns a iterator to iterate over the records in the batch.
func (wb *WriteBatch) NewIterator() *WriteBatchIterator {
	data := wb.Data()
	if len(data) < 8+4 {
		return &WriteBatchIterator{}
	}
	return &WriteBatchIterator{data: data[12:]}
}

// Clear removes all the enqueued Put and Deletes.
func (wb *WriteBatch) Clear() {
	C.rocksdb_writebatch_clear(wb.c)
}

// Destroy deallocates the WriteBatch object.
func (wb *WriteBatch) Destroy() {
	C.rocksdb_writebatch_destroy(wb.c)
	wb.c = nil
}

// WriteBatchRecordType describes the type of a batch record.
type WriteBatchRecordType byte

// Types of batch records.
const (
	WriteBatchDeletionRecord                 WriteBatchRecordType = 0x0
	WriteBatchValueRecord                    WriteBatchRecordType = 0x1
	WriteBatchMergeRecord                    WriteBatchRecordType = 0x2
	WriteBatchLogDataRecord                  WriteBatchRecordType = 0x3
	WriteBatchCFDeletionRecord               WriteBatchRecordType = 0x4
	WriteBatchCFValueRecord                  WriteBatchRecordType = 0x5
	WriteBatchCFMergeRecord                  WriteBatchRecordType = 0x6
	WriteBatchSingleDeletionRecord           WriteBatchRecordType = 0x7
	WriteBatchCFSingleDeletionRecord         WriteBatchRecordType = 0x8
	WriteBatchBeginPrepareXIDRecord          WriteBatchRecordType = 0x9
	WriteBatchEndPrepareXIDRecord            WriteBatchRecordType = 0xA
	WriteBatchCommitXIDRecord                WriteBatchRecordType = 0xB
	WriteBatchRollbackXIDRecord              WriteBatchRecordType = 0xC
	WriteBatchNoopRecord                     WriteBatchRecordType = 0xD
	WriteBatchRangeDeletion                  WriteBatchRecordType = 0xF
	WriteBatchCFRangeDeletion                WriteBatchRecordType = 0xE
	WriteBatchCFBlobIndex                    WriteBatchRecordType = 0x10
	WriteBatchBlobIndex                      WriteBatchRecordType = 0x11
	WriteBatchBeginPersistedPrepareXIDRecord WriteBatchRecordType = 0x12
	WriteBatchNotUsedRecord                  WriteBatchRecordType = 0x7F
)

// WriteBatchRecord represents a record inside a WriteBatch.
type WriteBatchRecord struct {
	CF    int
	Key   []byte
	Value []byte
	Blob  []byte
	Type  WriteBatchRecordType
}

// WriteBatchIterator represents a iterator to iterator over records.
type WriteBatchIterator struct {
	data   []byte
	record WriteBatchRecord
	err    error
}

// Next returns the next record.
// Returns false if no further record exists.
func (iter *WriteBatchIterator) Next() bool {
	if iter.err != nil || len(iter.data) == 0 {
		return false
	}
	// reset the current record
	iter.record.CF = 0
	iter.record.Key = nil
	iter.record.Value = nil
	iter.record.Blob = nil

	// parse the record type
	iter.record.Type = iter.decodeRecType()

	switch iter.record.Type {
	case
		WriteBatchDeletionRecord,
		WriteBatchSingleDeletionRecord:
		iter.record.Key = iter.decodeSlice()
	case
		WriteBatchCFDeletionRecord,
		WriteBatchCFSingleDeletionRecord:
		iter.record.CF = int(iter.decodeVarint())
		if iter.err == nil {
			iter.record.Key = iter.decodeSlice()
		}
	case
		WriteBatchValueRecord,
		WriteBatchMergeRecord,
		WriteBatchRangeDeletion,
		WriteBatchBlobIndex:
		iter.record.Key = iter.decodeSlice()
		if iter.err == nil {
			iter.record.Value = iter.decodeSlice()
		}
	case
		WriteBatchCFValueRecord,
		WriteBatchCFRangeDeletion,
		WriteBatchCFMergeRecord,
		WriteBatchCFBlobIndex:
		iter.record.CF = int(iter.decodeVarint())
		if iter.err == nil {
			iter.record.Key = iter.decodeSlice()
		}
		if iter.err == nil {
			iter.record.Value = iter.decodeSlice()
		}
	case WriteBatchLogDataRecord:
		iter.record.Blob = iter.decodeSlice()
	case
		WriteBatchNoopRecord,
		WriteBatchBeginPrepareXIDRecord,
		WriteBatchBeginPersistedPrepareXIDRecord:
	case
		WriteBatchEndPrepareXIDRecord,
		WriteBatchCommitXIDRecord,
		WriteBatchRollbackXIDRecord:
		iter.record.Blob = iter.decodeSlice()
	default:
		iter.err = errors.New("unsupported wal record type")
	}

	return iter.err == nil

}

// Record returns the current record.
func (iter *WriteBatchIterator) Record() *WriteBatchRecord {
	return &iter.record
}

// Error returns the error if the iteration is failed.
func (iter *WriteBatchIterator) Error() error {
	return iter.err
}

func (iter *WriteBatchIterator) decodeSlice() []byte {
	l := int(iter.decodeVarint())
	if l > len(iter.data) {
		iter.err = io.ErrShortBuffer
	}
	if iter.err != nil {
		return []byte{}
	}
	ret := iter.data[:l]
	iter.data = iter.data[l:]
	return ret
}

func (iter *WriteBatchIterator) decodeRecType() WriteBatchRecordType {
	if len(iter.data) == 0 {
		iter.err = io.ErrShortBuffer
		return WriteBatchNotUsedRecord
	}
	t := iter.data[0]
	iter.data = iter.data[1:]
	return WriteBatchRecordType(t)
}

func (iter *WriteBatchIterator) decodeVarint() uint64 {
	var n int
	var x uint64
	for shift := uint(0); shift < 64 && n < len(iter.data); shift += 7 {
		b := uint64(iter.data[n])
		n++
		x |= (b & 0x7F) << shift
		if (b & 0x80) == 0 {
			iter.data = iter.data[n:]
			return x
		}
	}
	if n == len(iter.data) {
		iter.err = io.ErrShortBuffer
	} else {
		iter.err = errors.New("malformed varint")
	}
	return 0
}
<commit_msg>rm unnecessary value/blob/xid distinction<commit_after>package gorocksdb

// #include "rocksdb/c.h"
import "C"
import (
	"errors"
	"io"
)

// WriteBatch is a batching of Puts, Merges and Deletes.
type WriteBatch struct {
	c *C.rocksdb_writebatch_t
}

// NewWriteBatch create a WriteBatch object.
func NewWriteBatch() *WriteBatch {
	return NewNativeWriteBatch(C.rocksdb_writebatch_create())
}

// NewNativeWriteBatch create a WriteBatch object.
func NewNativeWriteBatch(c *C.rocksdb_writebatch_t) *WriteBatch {
	return &WriteBatch{c}
}

// WriteBatchFrom creates a write batch from a serialized WriteBatch.
func WriteBatchFrom(data []byte) *WriteBatch {
	return NewNativeWriteBatch(C.rocksdb_writebatch_create_from(byteToChar(data), C.size_t(len(data))))
}

// Put queues a key-value pair.
func (wb *WriteBatch) Put(key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_put(wb.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// PutCF queues a key-value pair in a column family.
func (wb *WriteBatch) PutCF(cf *ColumnFamilyHandle, key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_put_cf(wb.c, cf.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// Merge queues a merge of "value" with the existing value of "key".
func (wb *WriteBatch) Merge(key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_merge(wb.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// MergeCF queues a merge of "value" with the existing value of "key" in a
// column family.
func (wb *WriteBatch) MergeCF(cf *ColumnFamilyHandle, key, value []byte) {
	cKey := byteToChar(key)
	cValue := byteToChar(value)
	C.rocksdb_writebatch_merge_cf(wb.c, cf.c, cKey, C.size_t(len(key)), cValue, C.size_t(len(value)))
}

// Delete queues a deletion of the data at key.
func (wb *WriteBatch) Delete(key []byte) {
	cKey := byteToChar(key)
	C.rocksdb_writebatch_delete(wb.c, cKey, C.size_t(len(key)))
}

// DeleteCF queues a deletion of the data at key in a column family.
func (wb *WriteBatch) DeleteCF(cf *ColumnFamilyHandle, key []byte) {
	cKey := byteToChar(key)
	C.rocksdb_writebatch_delete_cf(wb.c, cf.c, cKey, C.size_t(len(key)))
}

// Data returns the serialized version of this batch.
func (wb *WriteBatch) Data() []byte {
	var cSize C.size_t
	cValue := C.rocksdb_writebatch_data(wb.c, &cSize)
	return charToByte(cValue, cSize)
}

// Count returns the number of updates in the batch.
func (wb *WriteBatch) Count() int {
	return int(C.rocksdb_writebatch_count(wb.c))
}

// NewIterator returns a iterator to iterate over the records in the batch.
func (wb *WriteBatch) NewIterator() *WriteBatchIterator {
	data := wb.Data()
	if len(data) < 8+4 {
		return &WriteBatchIterator{}
	}
	return &WriteBatchIterator{data: data[12:]}
}

// Clear removes all the enqueued Put and Deletes.
func (wb *WriteBatch) Clear() {
	C.rocksdb_writebatch_clear(wb.c)
}

// Destroy deallocates the WriteBatch object.
func (wb *WriteBatch) Destroy() {
	C.rocksdb_writebatch_destroy(wb.c)
	wb.c = nil
}

// WriteBatchRecordType describes the type of a batch record.
type WriteBatchRecordType byte

// Types of batch records.
const (
	WriteBatchDeletionRecord                 WriteBatchRecordType = 0x0
	WriteBatchValueRecord                    WriteBatchRecordType = 0x1
	WriteBatchMergeRecord                    WriteBatchRecordType = 0x2
	WriteBatchLogDataRecord                  WriteBatchRecordType = 0x3
	WriteBatchCFDeletionRecord               WriteBatchRecordType = 0x4
	WriteBatchCFValueRecord                  WriteBatchRecordType = 0x5
	WriteBatchCFMergeRecord                  WriteBatchRecordType = 0x6
	WriteBatchSingleDeletionRecord           WriteBatchRecordType = 0x7
	WriteBatchCFSingleDeletionRecord         WriteBatchRecordType = 0x8
	WriteBatchBeginPrepareXIDRecord          WriteBatchRecordType = 0x9
	WriteBatchEndPrepareXIDRecord            WriteBatchRecordType = 0xA
	WriteBatchCommitXIDRecord                WriteBatchRecordType = 0xB
	WriteBatchRollbackXIDRecord              WriteBatchRecordType = 0xC
	WriteBatchNoopRecord                     WriteBatchRecordType = 0xD
	WriteBatchRangeDeletion                  WriteBatchRecordType = 0xF
	WriteBatchCFRangeDeletion                WriteBatchRecordType = 0xE
	WriteBatchCFBlobIndex                    WriteBatchRecordType = 0x10
	WriteBatchBlobIndex                      WriteBatchRecordType = 0x11
	WriteBatchBeginPersistedPrepareXIDRecord WriteBatchRecordType = 0x12
	WriteBatchNotUsedRecord                  WriteBatchRecordType = 0x7F
)

// WriteBatchRecord represents a record inside a WriteBatch.
type WriteBatchRecord struct {
	CF    int
	Key   []byte
	Value []byte
	Type  WriteBatchRecordType
}

// WriteBatchIterator represents a iterator to iterator over records.
type WriteBatchIterator struct {
	data   []byte
	record WriteBatchRecord
	err    error
}

// Next returns the next record.
// Returns false if no further record exists.
func (iter *WriteBatchIterator) Next() bool {
	if iter.err != nil || len(iter.data) == 0 {
		return false
	}
	// reset the current record
	iter.record.CF = 0
	iter.record.Key = nil
	iter.record.Value = nil

	// parse the record type
	iter.record.Type = iter.decodeRecType()

	switch iter.record.Type {
	case
		WriteBatchDeletionRecord,
		WriteBatchSingleDeletionRecord:
		iter.record.Key = iter.decodeSlice()
	case
		WriteBatchCFDeletionRecord,
		WriteBatchCFSingleDeletionRecord:
		iter.record.CF = int(iter.decodeVarint())
		if iter.err == nil {
			iter.record.Key = iter.decodeSlice()
		}
	case
		WriteBatchValueRecord,
		WriteBatchMergeRecord,
		WriteBatchRangeDeletion,
		WriteBatchBlobIndex:
		iter.record.Key = iter.decodeSlice()
		if iter.err == nil {
			iter.record.Value = iter.decodeSlice()
		}
	case
		WriteBatchCFValueRecord,
		WriteBatchCFRangeDeletion,
		WriteBatchCFMergeRecord,
		WriteBatchCFBlobIndex:
		iter.record.CF = int(iter.decodeVarint())
		if iter.err == nil {
			iter.record.Key = iter.decodeSlice()
		}
		if iter.err == nil {
			iter.record.Value = iter.decodeSlice()
		}
	case WriteBatchLogDataRecord:
		iter.record.Value = iter.decodeSlice()
	case
		WriteBatchNoopRecord,
		WriteBatchBeginPrepareXIDRecord,
		WriteBatchBeginPersistedPrepareXIDRecord:
	case
		WriteBatchEndPrepareXIDRecord,
		WriteBatchCommitXIDRecord,
		WriteBatchRollbackXIDRecord:
		iter.record.Value = iter.decodeSlice()
	default:
		iter.err = errors.New("unsupported wal record type")
	}

	return iter.err == nil

}

// Record returns the current record.
func (iter *WriteBatchIterator) Record() *WriteBatchRecord {
	return &iter.record
}

// Error returns the error if the iteration is failed.
func (iter *WriteBatchIterator) Error() error {
	return iter.err
}

func (iter *WriteBatchIterator) decodeSlice() []byte {
	l := int(iter.decodeVarint())
	if l > len(iter.data) {
		iter.err = io.ErrShortBuffer
	}
	if iter.err != nil {
		return []byte{}
	}
	ret := iter.data[:l]
	iter.data = iter.data[l:]
	return ret
}

func (iter *WriteBatchIterator) decodeRecType() WriteBatchRecordType {
	if len(iter.data) == 0 {
		iter.err = io.ErrShortBuffer
		return WriteBatchNotUsedRecord
	}
	t := iter.data[0]
	iter.data = iter.data[1:]
	return WriteBatchRecordType(t)
}

func (iter *WriteBatchIterator) decodeVarint() uint64 {
	var n int
	var x uint64
	for shift := uint(0); shift < 64 && n < len(iter.data); shift += 7 {
		b := uint64(iter.data[n])
		n++
		x |= (b & 0x7F) << shift
		if (b & 0x80) == 0 {
			iter.data = iter.data[n:]
			return x
		}
	}
	if n == len(iter.data) {
		iter.err = io.ErrShortBuffer
	} else {
		iter.err = errors.New("malformed varint")
	}
	return 0
}
<|endoftext|>


<commit_before>//wsserver.go
package ws

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/jayaramsankara/gotell/apns"
	"gopkg.in/redis.v5"
	"log"
	"net/http"
	"os"
	"time"
	"github.com/satori/go.uuid"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 30 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512

	// Max NUmber of Redis connections maintained for publishing events
	// This is same as the Go Channel buffer size for sending events for redis
	maxRedisConn = 50
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

var clientConnections = map[string][]*wsconnection{}

var redisSender chan *NotifyData

var receiver *redis.PubSub

var logs = log.New(os.Stdout, "INFO", log.LstdFlags)

var Logs = logs

type wsconnection struct {
	// The websocket connection.
	ws       *websocket.Conn
	clientId string
    id  string
	//The redis pubsubs channel
	// Buffered channel of outbound messages.
	//receive *redis.PubSub
	send   chan ([]byte)
	active bool
}

type redisclients struct {
	receiver *redis.PubSub
	sender   *redis.Client
}

type WsMessage struct {
	Message string `json:"message"`
}

type NotifyData struct {
	ClientId string
	Message  string
}

func (conn *wsconnection) Close() {
	conn.write(websocket.CloseMessage, []byte{})
	conn.ws.Close()
}

func (conn *wsconnection) String() (string) {
	return conn.clientId+" : "+conn.id
}

func (conn *wsconnection) sendMessages() {
	logs.Println("Initing sendMessages for client  " + conn.String())
	clientId := conn.clientId
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		logs.Println("Exiting sendMessages for client  : " + conn.String())
		conn.active = false
		logs.Println("Closing websocket connection for ", conn.String())
		conn.Close()

		currentConnections := clientConnections[clientId]
		if len(currentConnections) == 1 {
			logs.Println("Removing subscription to redis channel for ", conn.String())
			receiver.Unsubscribe(conn.clientId)
		}
		logs.Println("Exiting sendMessages. Removing the connection mapped to " + conn.String())
		delete(clientConnections, conn.clientId)
	}()

	for {
		select {
		case message, ok := <-conn.send:
			if !ok {
				log.Println("No more messages to be sent to WS connection from channel for  ", conn.String())
				return
			}
			logs.Println("Sending WS message for client  " + conn.String())
			if err := conn.write(websocket.TextMessage, message); err != nil {
				log.Println("Error while sending WS message  ", conn.String(), message, err)
				return
			}
		case <-ticker.C:
			logs.Println("Sending Ping WS message for client  " + conn.String())
			if err := conn.write(websocket.PingMessage, []byte{}); err != nil {
				log.Println("Error while sending WS ping message  ", conn.String(), err)
				return
			}
		}
	}

}

func (conn *wsconnection) receiveMessages() {
	logs.Println("Initing receiveMessages for client  " + conn.String())
	go func() {
		for {
			if _, _, err := conn.ws.NextReader(); err != nil {
				log.Println("Error while receiving WS pong message  ", conn.String(), err)
				conn.active = false
				conn.Close()
				break
			}
		}
	}()

	conn.ws.SetReadLimit(maxMessageSize)
	conn.ws.SetReadDeadline(time.Now().Add(pongWait))
	conn.ws.SetPongHandler(func(string) error {
		logs.Println("PongHandler for client  " + conn.String())
		conn.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})
}

// write writes a message with the given message type and payload.
func (conn *wsconnection) write(messageType int, payload []byte) error {
	conn.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return conn.ws.WriteMessage(messageType, payload)
}

func InitPubSub(redisConf *redis.Options) error {
	redisSender = make(chan *NotifyData, redisConf.PoolSize)
	receiver, _ = redis.NewClient(redisConf).Subscribe()

	var publisher = redis.NewClient(redisConf)

	logs.Println("Initialized redis clients for pub and sub.")

	//Init Redis receiver
	go func() {
		for {
			var msgi, err = receiver.Receive()
			if err != nil {
				log.Println("Error while receive message from redis pubsub receiver", err)
				// handle failure.. reinit redis pub sub
				log.Println("Reinitializing Redis PubSub.. and exiting the receive handler routine")
				close(redisSender)
				receiver.Close()
				publisher.Close()
				InitPubSub(redisConf)
				return

			} else {

				switch msg := msgi.(type) {
				case *redis.Subscription:
					logs.Println("Received messagefrom Redis ", msg.Kind, msg.Channel)
				case *redis.Message:
					logs.Println("Received message from Redis ", msg.Payload, msg.Channel)
					go func(clientId string, message string) {

						connections := clientConnections[clientId]
						for cnt := range connections {
							logs.Println("Sending the message to WS  client  ", message, connections[cnt].String())
							connections[cnt].send <- []byte(message)
						}

					}(msg.Channel, msg.Payload)

				case *redis.Pong:
					logs.Println("Pong message from Redis : ", msg)
				default:
					log.Printf("Error unknown message from Redis : %#v", msgi)
				}

			}

		}

	}()

	go func(msgsForRedis chan *NotifyData) {
		for {
			data, ok := <-msgsForRedis
			if !ok {
				log.Println("RedisSender channel seems to be closed. Exiting the routine")
				return
			}
			logs.Println("Received notification data from redisSender. ", data.ClientId)
			go func() {
				logs.Println("Publishing message to the Redis ", data.Message, data.ClientId)
				err := publisher.Publish(data.ClientId, data.Message).Err()
				if err != nil {
					log.Println("Error in publishing event to redis", err)
				}
			}()

		}

	}(redisSender)
	return nil
}

func ServeApns(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	deviceToken := vars["devicetoken"]

	//extract body

	decoder := json.NewDecoder(r.Body)
	var data apns.ApnsMessage
	err := decoder.Decode(&data)

	if err != nil {
		log.Println("Error while extracting the apns message.", err)
		w.WriteHeader(http.StatusInternalServerError)

	} else {
		// send data to conn
		logs.Println("Handling apns:  The extracted message is : ", data.Message, data.Badge, data.Sound)
		apns.Notify(&data, deviceToken)
		w.WriteHeader(http.StatusOK)
	}

}

//serveNotify receives the API, parses the body and sends the message to the corresponding
// websocket. Returns error if no websocket conn exists for a client id or send fails
func ServeNotify(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	clientId := vars["clientid"]

	//extract body

	decoder := json.NewDecoder(r.Body)
	var data WsMessage
	err := decoder.Decode(&data)

	if err != nil {
		log.Println("Error while extracting the message.", err)
		w.WriteHeader(http.StatusInternalServerError)

	} else {
		// send data to conn
		logs.Println("Handling notify:  The extracted message is : ", data.Message, clientId)
		notifyData := &NotifyData{
			ClientId: clientId,
			Message:  data.Message,
		}
		logs.Println("Handling notify:  Sending notification data to redisSender ", clientId)
		redisSender <- notifyData
		w.WriteHeader(http.StatusOK)
	}

}

// serverWs handles websocket requests from the peer.
func ServeWs(w http.ResponseWriter, r *http.Request) {

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error in accepting websocket connection", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	//new websocket connection
	vars := mux.Vars(r)
	clientId := vars["clientid"]
	logs.Println("Creating new wsconnection for client : " + clientId)

	currentConnections := clientConnections[clientId]
	//Subscribe for a client only for the first connection.
	if len(currentConnections) == 0 {
		// Initialize redis client as subscriber

		err = receiver.Subscribe(clientId)
		if err != nil {
			errMsg := "Failed to subscribe to message channel for " + clientId
			log.Println(errMsg, err)
			ws.WriteMessage(websocket.CloseInternalServerErr, []byte(errMsg))
			ws.Close()
			return
		}
	}

	conn := &wsconnection{active: true, clientId: clientId, id: newUUID() , ws: ws, send: make(chan []byte, 256)}
	logs.Println("Adding clientId-WsConn mapping for client  " + conn.String())

	modifiedConnections := append(currentConnections, conn)

	clientConnections[clientId] = modifiedConnections
	go conn.sendMessages()
	conn.receiveMessages()
}

func newUUID() (string) {

	u1 := uuid.NewV4()
	return u1.String()
}
<commit_msg>More logs<commit_after>//wsserver.go
package ws

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
	"github.com/jayaramsankara/gotell/apns"
	"gopkg.in/redis.v5"
	"log"
	"net/http"
	"os"
	"time"
	"github.com/satori/go.uuid"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 30 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512

	// Max NUmber of Redis connections maintained for publishing events
	// This is same as the Go Channel buffer size for sending events for redis
	maxRedisConn = 50
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin:     func(r *http.Request) bool { return true },
}

var clientConnections = map[string][]*wsconnection{}

var redisSender chan *NotifyData

var receiver *redis.PubSub

var logs = log.New(os.Stdout, "INFO", log.LstdFlags)

var Logs = logs

type wsconnection struct {
	// The websocket connection.
	ws       *websocket.Conn
	clientId string
    id  string
	//The redis pubsubs channel
	// Buffered channel of outbound messages.
	//receive *redis.PubSub
	send   chan ([]byte)
	active bool
}

type redisclients struct {
	receiver *redis.PubSub
	sender   *redis.Client
}

type WsMessage struct {
	Message string `json:"message"`
}

type NotifyData struct {
	ClientId string
	Message  string
}

func (conn *wsconnection) Close() {
	conn.write(websocket.CloseMessage, []byte{})
	conn.ws.Close()
}

func (conn *wsconnection) String() (string) {
	return conn.clientId+" : "+conn.id
}

func (conn *wsconnection) sendMessages() {
	logs.Println("Initing sendMessages for client  " + conn.String())
	clientId := conn.clientId
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		logs.Println("Exiting sendMessages for client  : " + conn.String())
		conn.active = false
		logs.Println("Closing websocket connection for ", conn.String())
		conn.Close()

		currentConnections := clientConnections[clientId]
		if len(currentConnections) == 1 {
			logs.Println("Removing subscription to redis channel for ", conn.String())
			receiver.Unsubscribe(conn.clientId)
		}
		logs.Println("Exiting sendMessages. Removing the connection mapped to " + conn.String())
		delete(clientConnections, conn.clientId)
	}()

	for {
		select {
		case message, ok := <-conn.send:
			if !ok {
				log.Println("No more messages to be sent to WS connection from channel for  ", conn.String())
				return
			}
			logs.Println("Sending WS message for client  " + conn.String())
			if err := conn.write(websocket.TextMessage, message); err != nil {
				log.Println("Error while sending WS message  ", conn.String(), message, err)
				return
			}
		case <-ticker.C:
			logs.Println("Sending Ping WS message for client  " + conn.String())
			if err := conn.write(websocket.PingMessage, []byte{}); err != nil {
				log.Println("Error while sending WS ping message  ", conn.String(), err)
				return
			}
		}
	}

}

func (conn *wsconnection) receiveMessages() {
	logs.Println("Initing receiveMessages for client  " + conn.String())
	go func() {
		for {
			if _, _, err := conn.ws.NextReader(); err != nil {
				log.Println("Error while receiving WS pong message  ", conn.String(), err)
				conn.active = false
				conn.Close()
				break
			}
		}
	}()

	conn.ws.SetReadLimit(maxMessageSize)
	conn.ws.SetReadDeadline(time.Now().Add(pongWait))
	conn.ws.SetPongHandler(func(string) error {
		logs.Println("PongHandler for client  " + conn.String())
		conn.ws.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})
}

// write writes a message with the given message type and payload.
func (conn *wsconnection) write(messageType int, payload []byte) error {
	conn.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return conn.ws.WriteMessage(messageType, payload)
}

func InitPubSub(redisConf *redis.Options) error {
	redisSender = make(chan *NotifyData, redisConf.PoolSize)
	receiver, _ = redis.NewClient(redisConf).Subscribe()

	var publisher = redis.NewClient(redisConf)

	logs.Println("Initialized redis clients for pub and sub.")

	//Init Redis receiver
	go func() {
		for {
			var msgi, err = receiver.Receive()
			if err != nil {
				log.Println("Error while receive message from redis pubsub receiver", err)
				// handle failure.. reinit redis pub sub
				log.Println("Reinitializing Redis PubSub.. and exiting the receive handler routine")
				close(redisSender)
				receiver.Close()
				publisher.Close()
				InitPubSub(redisConf)
				return

			} else {

				switch msg := msgi.(type) {
				case *redis.Subscription:
					logs.Println("Received messagefrom Redis ", msg.Kind, msg.Channel)
				case *redis.Message:
					logs.Println("Received message from Redis ", msg.Payload, msg.Channel)
					go func(clientId string, message string) {
						logs.Println("Attempting to send the message to WS  connections for client ", message, clientId)
						connections := clientConnections[clientId]
						for cnt := range connections {
							logs.Println("Sending the message to WS  client  ", message, connections[cnt].String())
							connections[cnt].send <- []byte(message)
						}

					}(msg.Channel, msg.Payload)

				case *redis.Pong:
					logs.Println("Pong message from Redis : ", msg)
				default:
					log.Printf("Error unknown message from Redis : %#v", msgi)
				}

			}

		}

	}()

	go func(msgsForRedis chan *NotifyData) {
		for {
			data, ok := <-msgsForRedis
			if !ok {
				log.Println("RedisSender channel seems to be closed. Exiting the routine")
				return
			}
			logs.Println("Received notification data from redisSender. ", data.ClientId)
			go func() {
				logs.Println("Publishing message to the Redis ", data.Message, data.ClientId)
				err := publisher.Publish(data.ClientId, data.Message).Err()
				if err != nil {
					log.Println("Error in publishing event to redis", err)
				}
			}()

		}

	}(redisSender)
	return nil
}

func ServeApns(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	deviceToken := vars["devicetoken"]

	//extract body

	decoder := json.NewDecoder(r.Body)
	var data apns.ApnsMessage
	err := decoder.Decode(&data)

	if err != nil {
		log.Println("Error while extracting the apns message.", err)
		w.WriteHeader(http.StatusInternalServerError)

	} else {
		// send data to conn
		logs.Println("Handling apns:  The extracted message is : ", data.Message, data.Badge, data.Sound)
		apns.Notify(&data, deviceToken)
		w.WriteHeader(http.StatusOK)
	}

}

//serveNotify receives the API, parses the body and sends the message to the corresponding
// websocket. Returns error if no websocket conn exists for a client id or send fails
func ServeNotify(w http.ResponseWriter, r *http.Request) {

	vars := mux.Vars(r)
	clientId := vars["clientid"]

	//extract body

	decoder := json.NewDecoder(r.Body)
	var data WsMessage
	err := decoder.Decode(&data)

	if err != nil {
		log.Println("Error while extracting the message.", err)
		w.WriteHeader(http.StatusInternalServerError)

	} else {
		// send data to conn
		logs.Println("Handling notify:  The extracted message is : ", data.Message, clientId)
		notifyData := &NotifyData{
			ClientId: clientId,
			Message:  data.Message,
		}
		logs.Println("Handling notify:  Sending notification data to redisSender ", clientId)
		redisSender <- notifyData
		w.WriteHeader(http.StatusOK)
	}

}

// serverWs handles websocket requests from the peer.
func ServeWs(w http.ResponseWriter, r *http.Request) {

	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error in accepting websocket connection", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	//new websocket connection
	vars := mux.Vars(r)
	clientId := vars["clientid"]
	logs.Println("Creating new wsconnection for client : " + clientId)

	currentConnections := clientConnections[clientId]
	//Subscribe for a client only for the first connection.
	if len(currentConnections) == 0 {
		// Initialize redis client as subscriber

		err = receiver.Subscribe(clientId)
		if err != nil {
			errMsg := "Failed to subscribe to message channel for " + clientId
			log.Println(errMsg, err)
			ws.WriteMessage(websocket.CloseInternalServerErr, []byte(errMsg))
			ws.Close()
			return
		}
	}

	conn := &wsconnection{active: true, clientId: clientId, id: newUUID() , ws: ws, send: make(chan []byte, 256)}
	logs.Println("Adding clientId-WsConn mapping for client  " + conn.String())

	modifiedConnections := append(currentConnections, conn)

	clientConnections[clientId] = modifiedConnections
	go conn.sendMessages()
	conn.receiveMessages()
}

func newUUID() (string) {

	u1 := uuid.NewV4()
	return u1.String()
}
<|endoftext|>


<commit_before>package sqlx

import (
	"os"
	"path/filepath"

	"github.com/henrylee2cn/faygo"
	"github.com/henrylee2cn/faygo/ini"
)

// DBConfig is database connection config
type DBConfig struct {
	Name         string `ini:"-"`
	Enable       bool   `ini:"enable"`
	Driver       string `ini:"driver"` // driver: mssql | odbc(mssql) | mysql | mymysql | postgres | sqlite3 | oci8 | goracle
	Connstring   string `ini:"connstring"`
	MaxOpenConns int    `ini:"max_open_conns"`
	MaxIdleConns int    `ini:"max_idle_conns"`
	ShowSql      bool   `ini:"show_sql"`
	ColumnSnake  bool   `ini:"column_snake"` // the column name uses the snake style or remains unchanged
	StructTag    string `ini:"struct_tag"`   // default is 'db'
}

// default constant
const (
	DBCONFIG_FILE  = faygo.CONFIG_DIR + "sqlx.ini"
	DATABASE_DIR   = "database/"
	DEFAULTDB_NAME = "default"
)

var (
	dbConfigs     = map[string]*DBConfig{}
	defaultConfig = &DBConfig{
		Name:         DEFAULTDB_NAME,
		Driver:       "mysql",
		Connstring:   "root:@tcp(127.0.0.1:3306)/faygo?charset=utf8",
		MaxOpenConns: 100,
		MaxIdleConns: 100,
		ColumnSnake:  true,
		StructTag:    "db",
	}
)

func loadDBConfig() error {
	var cfg *ini.File
	var err error
	var exist bool
	cfg, err = ini.Load(DBCONFIG_FILE)
	if err != nil {
		os.MkdirAll(filepath.Dir(DBCONFIG_FILE), 0777)
		cfg, err = ini.LooseLoad(DBCONFIG_FILE)
		if err != nil {
			return err
		}
	} else {
		exist = true
	}
	var hadDefaultConfig bool
	for _, section := range cfg.Sections() {
		if section.Name() == ini.DEFAULT_SECTION {
			continue
		}
		var dbConfig *DBConfig
		if section.Name() == DEFAULTDB_NAME {
			dbConfig = defaultConfig
			hadDefaultConfig = true
		} else {
			dbConfig = &DBConfig{Name: section.Name()}
		}
		err := section.MapTo(dbConfig)
		if err != nil {
			return err
		}
		dbConfigs[dbConfig.Name] = dbConfig
	}
	if !exist {
		sec, _ := cfg.NewSection(DEFAULTDB_NAME)
		defaultConfig.Enable = true
		err := sec.ReflectFrom(defaultConfig)
		if err != nil {
			return err
		}
		dbConfigs[DEFAULTDB_NAME] = defaultConfig
		return cfg.SaveTo(DBCONFIG_FILE)
	}
	if !hadDefaultConfig {
		*defaultConfig = DBConfig{}
	}
	return nil
}
<commit_msg>ext/db/sqlx: remove usless config ‘show_sql’<commit_after>package sqlx

import (
	"os"
	"path/filepath"

	"github.com/henrylee2cn/faygo"
	"github.com/henrylee2cn/faygo/ini"
)

// DBConfig is database connection config
type DBConfig struct {
	Name         string `ini:"-"`
	Enable       bool   `ini:"enable"`
	Driver       string `ini:"driver"` // driver: mssql | odbc(mssql) | mysql | mymysql | postgres | sqlite3 | oci8 | goracle
	Connstring   string `ini:"connstring"`
	MaxOpenConns int    `ini:"max_open_conns"`
	MaxIdleConns int    `ini:"max_idle_conns"`
	ColumnSnake  bool   `ini:"column_snake"` // the column name uses the snake style or remains unchanged
	StructTag    string `ini:"struct_tag"`   // default is 'db'
}

// default constant
const (
	DBCONFIG_FILE  = faygo.CONFIG_DIR + "sqlx.ini"
	DATABASE_DIR   = "database/"
	DEFAULTDB_NAME = "default"
)

var (
	dbConfigs     = map[string]*DBConfig{}
	defaultConfig = &DBConfig{
		Name:         DEFAULTDB_NAME,
		Driver:       "mysql",
		Connstring:   "root:@tcp(127.0.0.1:3306)/faygo?charset=utf8",
		MaxOpenConns: 100,
		MaxIdleConns: 100,
		ColumnSnake:  true,
		StructTag:    "db",
	}
)

func loadDBConfig() error {
	var cfg *ini.File
	var err error
	var exist bool
	cfg, err = ini.Load(DBCONFIG_FILE)
	if err != nil {
		os.MkdirAll(filepath.Dir(DBCONFIG_FILE), 0777)
		cfg, err = ini.LooseLoad(DBCONFIG_FILE)
		if err != nil {
			return err
		}
	} else {
		exist = true
	}
	var hadDefaultConfig bool
	for _, section := range cfg.Sections() {
		if section.Name() == ini.DEFAULT_SECTION {
			continue
		}
		var dbConfig *DBConfig
		if section.Name() == DEFAULTDB_NAME {
			dbConfig = defaultConfig
			hadDefaultConfig = true
		} else {
			dbConfig = &DBConfig{Name: section.Name()}
		}
		err := section.MapTo(dbConfig)
		if err != nil {
			return err
		}
		dbConfigs[dbConfig.Name] = dbConfig
	}
	if !exist {
		sec, _ := cfg.NewSection(DEFAULTDB_NAME)
		defaultConfig.Enable = true
		err := sec.ReflectFrom(defaultConfig)
		if err != nil {
			return err
		}
		dbConfigs[DEFAULTDB_NAME] = defaultConfig
		return cfg.SaveTo(DBCONFIG_FILE)
	}
	if !hadDefaultConfig {
		*defaultConfig = DBConfig{}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/codegangsta/cli"
	"os"
	"path"
)

func init() {
	cli.AppHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

	cli.CommandHelpTemplate = `{{$DISCOVERY := (eq .Name "monitor")}}Usage: ` + path.Base(os.Args[0]) + ` {{.Name}}{{if .Flags}} [OPTIONS]{{end}} {{if $DISCOVERY}}<discovery>{{end}}

{{.Usage}}{{if $DISCOVERY}}

Arguments:
    <discovery>    discovery service to use [$SWARM_DISCOVERY]
                    * etcd://<ip1>,<ip2>/<path>{{end}}{{if .Flags}}

Options:
   {{range .Flags}}{{.}}
   {{end}}{{end}}
`
}
<commit_msg>FIX: watch command help text missing<commit_after>package main

import (
	"github.com/codegangsta/cli"
	"os"
	"path"
)

func init() {
	cli.AppHelpTemplate = `Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

{{.Usage}}

Version: {{.Version}}{{if or .Author .Email}}

Author:{{if .Author}}
  {{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}}
  {{.Email}}{{end}}{{end}}
{{if .Flags}}
Options:
  {{range .Flags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

	cli.CommandHelpTemplate = `{{$DISCOVERY := or (eq .Name "monitor") (eq .Name "watch")}}Usage: ` + path.Base(os.Args[0]) + ` {{.Name}}{{if .Flags}} [OPTIONS]{{end}} {{if $DISCOVERY}}<discovery>{{end}}

{{.Usage}}{{if $DISCOVERY}}

Arguments:
    <discovery>    discovery service to use [$SWARM_DISCOVERY]
                    * etcd://<ip1>,<ip2>/<path>{{end}}{{if .Flags}}

Options:
   {{range .Flags}}{{.}}
   {{end}}{{end}}
`
}
<|endoftext|>