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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"text/template"
	"unicode"
	"unicode/utf8"
)

// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
	return c.Run != nil
}

// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
	cmdBuild,
	cmdClean,
	cmdDoc,
	cmdFix,
	cmdFmt,
	cmdGet,
	cmdInstall,
	cmdList,
	cmdRun,
	cmdTest,
	cmdTool,
	cmdVersion,
	cmdVet,

	helpGopath,
	helpImportpath,
	helpRemote,
	helpTestflag,
	helpTestfunc,
}

var exitStatus = 0
var exitMu sync.Mutex

func setExitStatus(n int) {
	exitMu.Lock()
	if exitStatus < n {
		exitStatus = n
	}
	exitMu.Unlock()
}

func main() {
	flag.Usage = usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}
			cmd.Run(cmd, args)
			exit()
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown command %#q\n\n", args[0])
	usage()
}

var usageTemplate = `Go is a tool for managing Go source code.

Usage: go command [arguments]

The commands are:
{{range .}}{{if .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "go help [command]" for more information about a command.

Additional help topics:
{{range .}}{{if not .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "go help [topic]" for more information about that topic.

`

var helpTemplate = `{{if .Run}}usage: go {{.UsageLine}}

{{end}}{{.Long | trim}}
`

var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
{{range .}}{{if .Short}}{{.Short | capitalize}}

{{end}}{{if .Run}}Usage:

	go {{.UsageLine}}

{{end}}{{.Long | trim}}

{{end}}*/
package documentation

// NOTE: cmdDoc is in fmt.go.
`

// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
	template.Must(t.Parse(text))
	if err := t.Execute(w, data); err != nil {
		panic(err)
	}
}

func capitalize(s string) string {
	if s == "" {
		return s
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToTitle(r)) + s[n:]
}

func printUsage(w io.Writer) {
	tmpl(w, usageTemplate, commands)
}

func usage() {
	printUsage(os.Stderr)
	os.Exit(2)
}

// help implements the 'help' command.
func help(args []string) {
	if len(args) == 0 {
		printUsage(os.Stdout)
		// not exit 2: succeeded at 'go help'.
		return
	}
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
		os.Exit(2) // failed at 'go help'
	}

	arg := args[0]

	// 'go help documentation' generates doc.go.
	if arg == "documentation" {
		buf := new(bytes.Buffer)
		printUsage(buf)
		usage := &Command{Long: buf.String()}
		tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == arg {
			tmpl(os.Stdout, helpTemplate, cmd)
			// not exit 2: succeeded at 'go help cmd'.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run 'go help'.\n", arg)
	os.Exit(2) // failed at 'go help cmd'
}

// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
	if len(args) == 0 {
		return []string{"."}
	}
	var out []string
	for _, a := range args {
		if isLocalPath(a) && strings.Contains(a, "...") {
			out = append(out, allPackagesInFS(a)...)
			continue
		}
		if a == "all" || a == "std" || strings.Contains(a, "...") {
			out = append(out, allPackages(a)...)
			continue
		}
		out = append(out, a)
	}
	return out
}

var atexitFuncs []func()

func atexit(f func()) {
	atexitFuncs = append(atexitFuncs, f)
}

func exit() {
	for _, f := range atexitFuncs {
		f()
	}
	os.Exit(exitStatus)
}

func fatalf(format string, args ...interface{}) {
	errorf(format, args...)
	exit()
}

func errorf(format string, args ...interface{}) {
	log.Printf(format, args...)
	setExitStatus(1)
}

var logf = log.Printf

func exitIfErrors() {
	if exitStatus != 0 {
		exit()
	}
}

func run(cmdargs ...interface{}) {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		errorf("%v", err)
	}
}

func runOut(dir string, cmdargs ...interface{}) []byte {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		os.Stderr.Write(out)
		errorf("%v", err)
		out = nil
	}
	return out
}

// matchPattern(pattern)(name) reports whether
// name matches pattern.  Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
	re := regexp.QuoteMeta(pattern)
	re = strings.Replace(re, `\.\.\.`, `.*`, -1)
	reg := regexp.MustCompile(`^` + re + `$`)
	return func(name string) bool {
		return reg.MatchString(name)
	}
}

// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages)
// or a path including "...".
func allPackages(pattern string) []string {
	match := func(string) bool { return true }
	if pattern != "all" && pattern != "std" {
		match = matchPattern(pattern)
	}

	have := map[string]bool{
		"builtin": true, // ignore pseudo-package that exists only for documentation
	}
	if !buildContext.CgoEnabled {
		have["runtime/cgo"] = true // ignore during walk
	}
	var pkgs []string

	// Commands
	goroot := build.Path[0].Path
	cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
	filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
		if err != nil || !fi.IsDir() || path == cmd {
			return nil
		}
		name := path[len(cmd):]
		// Commands are all in cmd/, not in subdirectories.
		if strings.Contains(name, string(filepath.Separator)) {
			return filepath.SkipDir
		}

		_, err = build.ScanDir(path)
		if err != nil {
			return nil
		}

		// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
		name = "cmd/" + name
		if !have[name] {
			have[name] = true
			if match(name) {
				pkgs = append(pkgs, name)
			}
		}
		return nil
	})

	for _, t := range build.Path {
		if pattern == "std" && !t.Goroot {
			continue
		}
		src := t.SrcDir() + string(filepath.Separator)
		filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
			if err != nil || !fi.IsDir() || path == src {
				return nil
			}

			// Avoid .foo, _foo, and testdata directory trees.
			_, elem := filepath.Split(path)
			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
				return filepath.SkipDir
			}

			name := filepath.ToSlash(path[len(src):])
			if pattern == "std" && strings.Contains(name, ".") {
				return filepath.SkipDir
			}
			if have[name] {
				return nil
			}
			have[name] = true

			_, err = build.ScanDir(path)
			if err != nil && strings.Contains(err.Error(), "no Go source files") {
				return nil
			}

			if match(name) {
				pkgs = append(pkgs, name)
			}

			// Avoid go/build test data.
			// TODO: Move it into a testdata directory.
			if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
				return filepath.SkipDir
			}

			return nil
		})
	}

	if len(pkgs) == 0 {
		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
	}
	return pkgs
}

// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory.  There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
	// Find directory to begin the scan.
	// Could be smarter but this one optimization
	// is enough for now, since ... is usually at the
	// end of a path.
	i := strings.Index(pattern, "...")
	dir, _ := path.Split(pattern[:i])

	// pattern begins with ./ or ../.
	// path.Clean will discard the ./ but not the ../.
	// We need to preserve the ./ for pattern matching
	// and in the returned import paths.
	prefix := ""
	if strings.HasPrefix(pattern, "./") {
		prefix = "./"
	}
	match := matchPattern(pattern)

	var pkgs []string
	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
		if err != nil || !fi.IsDir() || path == dir {
			return nil
		}

		// Avoid .foo, _foo, and testdata directory trees.
		_, elem := filepath.Split(path)
		if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
			return filepath.SkipDir
		}

		name := prefix + filepath.ToSlash(path)
		if !match(name) {
			return nil
		}
		if _, err = build.ScanDir(path); err != nil {
			return nil
		}
		pkgs = append(pkgs, name)
		return nil
	})

	if len(pkgs) == 0 {
		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
	}
	return pkgs
}

// stringList's arguments should be a sequence of string or []string values.
// stringList flattens them into a single []string.
func stringList(args ...interface{}) []string {
	var x []string
	for _, arg := range args {
		switch arg := arg.(type) {
		case []string:
			x = append(x, arg...)
		case string:
			x = append(x, arg)
		default:
			panic("stringList: invalid argument")
		}
	}
	return x
}

// isLocalPath returns true if arg is an import path denoting
// a local file system directory.  That is, it returns true if the
// path begins with ./ or ../ .
func isLocalPath(arg string) bool {
	return arg == "." || arg == ".." || strings.HasPrefix(arg, "./") || strings.HasPrefix(arg, "../")
}
<commit_msg>cmd/go: fix 'go help <command>'<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"text/template"
	"unicode"
	"unicode/utf8"
)

// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

func (c *Command) Usage() {
	fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
	fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
	os.Exit(2)
}

// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
	return c.Run != nil
}

// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
	cmdBuild,
	cmdClean,
	cmdDoc,
	cmdFix,
	cmdFmt,
	cmdGet,
	cmdInstall,
	cmdList,
	cmdRun,
	cmdTest,
	cmdTool,
	cmdVersion,
	cmdVet,

	helpGopath,
	helpImportpath,
	helpRemote,
	helpTestflag,
	helpTestfunc,
}

var exitStatus = 0
var exitMu sync.Mutex

func setExitStatus(n int) {
	exitMu.Lock()
	if exitStatus < n {
		exitStatus = n
	}
	exitMu.Unlock()
}

func main() {
	flag.Usage = usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}
			cmd.Run(cmd, args)
			exit()
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown command %#q\n\n", args[0])
	usage()
}

var usageTemplate = `Go is a tool for managing Go source code.

Usage: go command [arguments]

The commands are:
{{range .}}{{if .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "go help [command]" for more information about a command.

Additional help topics:
{{range .}}{{if not .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use "go help [topic]" for more information about that topic.

`

var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}

{{end}}{{.Long | trim}}
`

var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
{{range .}}{{if .Short}}{{.Short | capitalize}}

{{end}}{{if .Runnable}}Usage:

	go {{.UsageLine}}

{{end}}{{.Long | trim}}

{{end}}*/
package documentation

// NOTE: cmdDoc is in fmt.go.
`

// tmpl executes the given template text on data, writing the result to w.
func tmpl(w io.Writer, text string, data interface{}) {
	t := template.New("top")
	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
	template.Must(t.Parse(text))
	if err := t.Execute(w, data); err != nil {
		panic(err)
	}
}

func capitalize(s string) string {
	if s == "" {
		return s
	}
	r, n := utf8.DecodeRuneInString(s)
	return string(unicode.ToTitle(r)) + s[n:]
}

func printUsage(w io.Writer) {
	tmpl(w, usageTemplate, commands)
}

func usage() {
	printUsage(os.Stderr)
	os.Exit(2)
}

// help implements the 'help' command.
func help(args []string) {
	if len(args) == 0 {
		printUsage(os.Stdout)
		// not exit 2: succeeded at 'go help'.
		return
	}
	if len(args) != 1 {
		fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n")
		os.Exit(2) // failed at 'go help'
	}

	arg := args[0]

	// 'go help documentation' generates doc.go.
	if arg == "documentation" {
		buf := new(bytes.Buffer)
		printUsage(buf)
		usage := &Command{Long: buf.String()}
		tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
		return
	}

	for _, cmd := range commands {
		if cmd.Name() == arg {
			tmpl(os.Stdout, helpTemplate, cmd)
			// not exit 2: succeeded at 'go help cmd'.
			return
		}
	}

	fmt.Fprintf(os.Stderr, "Unknown help topic %#q.  Run 'go help'.\n", arg)
	os.Exit(2) // failed at 'go help cmd'
}

// importPaths returns the import paths to use for the given command line.
func importPaths(args []string) []string {
	if len(args) == 0 {
		return []string{"."}
	}
	var out []string
	for _, a := range args {
		if isLocalPath(a) && strings.Contains(a, "...") {
			out = append(out, allPackagesInFS(a)...)
			continue
		}
		if a == "all" || a == "std" || strings.Contains(a, "...") {
			out = append(out, allPackages(a)...)
			continue
		}
		out = append(out, a)
	}
	return out
}

var atexitFuncs []func()

func atexit(f func()) {
	atexitFuncs = append(atexitFuncs, f)
}

func exit() {
	for _, f := range atexitFuncs {
		f()
	}
	os.Exit(exitStatus)
}

func fatalf(format string, args ...interface{}) {
	errorf(format, args...)
	exit()
}

func errorf(format string, args ...interface{}) {
	log.Printf(format, args...)
	setExitStatus(1)
}

var logf = log.Printf

func exitIfErrors() {
	if exitStatus != 0 {
		exit()
	}
}

func run(cmdargs ...interface{}) {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		errorf("%v", err)
	}
}

func runOut(dir string, cmdargs ...interface{}) []byte {
	cmdline := stringList(cmdargs...)
	cmd := exec.Command(cmdline[0], cmdline[1:]...)
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		os.Stderr.Write(out)
		errorf("%v", err)
		out = nil
	}
	return out
}

// matchPattern(pattern)(name) reports whether
// name matches pattern.  Pattern is a limited glob
// pattern in which '...' means 'any string' and there
// is no other special syntax.
func matchPattern(pattern string) func(name string) bool {
	re := regexp.QuoteMeta(pattern)
	re = strings.Replace(re, `\.\.\.`, `.*`, -1)
	reg := regexp.MustCompile(`^` + re + `$`)
	return func(name string) bool {
		return reg.MatchString(name)
	}
}

// allPackages returns all the packages that can be found
// under the $GOPATH directories and $GOROOT matching pattern.
// The pattern is either "all" (all packages), "std" (standard packages)
// or a path including "...".
func allPackages(pattern string) []string {
	match := func(string) bool { return true }
	if pattern != "all" && pattern != "std" {
		match = matchPattern(pattern)
	}

	have := map[string]bool{
		"builtin": true, // ignore pseudo-package that exists only for documentation
	}
	if !buildContext.CgoEnabled {
		have["runtime/cgo"] = true // ignore during walk
	}
	var pkgs []string

	// Commands
	goroot := build.Path[0].Path
	cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
	filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
		if err != nil || !fi.IsDir() || path == cmd {
			return nil
		}
		name := path[len(cmd):]
		// Commands are all in cmd/, not in subdirectories.
		if strings.Contains(name, string(filepath.Separator)) {
			return filepath.SkipDir
		}

		_, err = build.ScanDir(path)
		if err != nil {
			return nil
		}

		// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
		name = "cmd/" + name
		if !have[name] {
			have[name] = true
			if match(name) {
				pkgs = append(pkgs, name)
			}
		}
		return nil
	})

	for _, t := range build.Path {
		if pattern == "std" && !t.Goroot {
			continue
		}
		src := t.SrcDir() + string(filepath.Separator)
		filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
			if err != nil || !fi.IsDir() || path == src {
				return nil
			}

			// Avoid .foo, _foo, and testdata directory trees.
			_, elem := filepath.Split(path)
			if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
				return filepath.SkipDir
			}

			name := filepath.ToSlash(path[len(src):])
			if pattern == "std" && strings.Contains(name, ".") {
				return filepath.SkipDir
			}
			if have[name] {
				return nil
			}
			have[name] = true

			_, err = build.ScanDir(path)
			if err != nil && strings.Contains(err.Error(), "no Go source files") {
				return nil
			}

			if match(name) {
				pkgs = append(pkgs, name)
			}

			// Avoid go/build test data.
			// TODO: Move it into a testdata directory.
			if path == filepath.Join(build.Path[0].SrcDir(), "go/build") {
				return filepath.SkipDir
			}

			return nil
		})
	}

	if len(pkgs) == 0 {
		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
	}
	return pkgs
}

// allPackagesInFS is like allPackages but is passed a pattern
// beginning ./ or ../, meaning it should scan the tree rooted
// at the given directory.  There are ... in the pattern too.
func allPackagesInFS(pattern string) []string {
	// Find directory to begin the scan.
	// Could be smarter but this one optimization
	// is enough for now, since ... is usually at the
	// end of a path.
	i := strings.Index(pattern, "...")
	dir, _ := path.Split(pattern[:i])

	// pattern begins with ./ or ../.
	// path.Clean will discard the ./ but not the ../.
	// We need to preserve the ./ for pattern matching
	// and in the returned import paths.
	prefix := ""
	if strings.HasPrefix(pattern, "./") {
		prefix = "./"
	}
	match := matchPattern(pattern)

	var pkgs []string
	filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
		if err != nil || !fi.IsDir() || path == dir {
			return nil
		}

		// Avoid .foo, _foo, and testdata directory trees.
		_, elem := filepath.Split(path)
		if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
			return filepath.SkipDir
		}

		name := prefix + filepath.ToSlash(path)
		if !match(name) {
			return nil
		}
		if _, err = build.ScanDir(path); err != nil {
			return nil
		}
		pkgs = append(pkgs, name)
		return nil
	})

	if len(pkgs) == 0 {
		fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
	}
	return pkgs
}

// stringList's arguments should be a sequence of string or []string values.
// stringList flattens them into a single []string.
func stringList(args ...interface{}) []string {
	var x []string
	for _, arg := range args {
		switch arg := arg.(type) {
		case []string:
			x = append(x, arg...)
		case string:
			x = append(x, arg)
		default:
			panic("stringList: invalid argument")
		}
	}
	return x
}

// isLocalPath returns true if arg is an import path denoting
// a local file system directory.  That is, it returns true if the
// path begins with ./ or ../ .
func isLocalPath(arg string) bool {
	return arg == "." || arg == ".." || strings.HasPrefix(arg, "./") || strings.HasPrefix(arg, "../")
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gdamore/tcell"
	"io/ioutil"
	"os/user"
	"regexp"
	"strconv"
	"strings"
)

const defaultColorscheme = "default"

// Colorscheme is a map from string to style -- it represents a colorscheme
type Colorscheme map[string]tcell.Style

// The current colorscheme
var colorscheme Colorscheme

// InitColorscheme picks and initializes the colorscheme when micro starts
func InitColorscheme() {
	LoadDefaultColorscheme()
}

// LoadDefaultColorscheme loads the default colorscheme from ~/.micro/colorschemes
func LoadDefaultColorscheme() {
	usr, _ := user.Current()
	dir := usr.HomeDir
	LoadColorscheme(defaultColorscheme, dir+"/.micro/colorschemes")
}

// LoadColorscheme loads the given colorscheme from a directory
func LoadColorscheme(colorschemeName, dir string) {
	files, _ := ioutil.ReadDir(dir)
	for _, f := range files {
		if f.Name() == colorschemeName+".micro" {
			text, err := ioutil.ReadFile(dir + "/" + f.Name())
			if err != nil {
				fmt.Println("Error loading colorscheme:", err)
				continue
			}
			colorscheme = ParseColorscheme(string(text))
		}
	}
}

// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object
// Colorschemes are made up of color-link statements linking a color group to a list of colors
// For example, color-link keyword (blue,red) makes all keywords have a blue foreground and
// red background
func ParseColorscheme(text string) Colorscheme {
	parser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`)

	lines := strings.Split(text, "\n")

	c := make(Colorscheme)

	for _, line := range lines {
		if strings.TrimSpace(line) == "" ||
			strings.TrimSpace(line)[0] == '#' {
			// Ignore this line
			continue
		}

		matches := parser.FindSubmatch([]byte(line))
		if len(matches) == 3 {
			link := string(matches[1])
			colors := string(matches[2])

			c[link] = StringToStyle(colors)
		} else {
			fmt.Println("Color-link statement is not valid:", line)
		}
	}

	return c
}

// StringToStyle returns a style from a string
// The strings must be in the format "extra foregroundcolor,backgroundcolor"
// The 'extra' can be bold, reverse, or underline
func StringToStyle(str string) tcell.Style {
	var fg string
	var bg string
	split := strings.Split(str, ",")
	if len(split) > 1 {
		fg, bg = split[0], split[1]
	} else {
		fg = split[0]
	}
	fg = strings.TrimSpace(fg)
	bg = strings.TrimSpace(bg)

	style := tcell.StyleDefault.Foreground(StringToColor(fg)).Background(StringToColor(bg))
	if strings.Contains(str, "bold") {
		style = style.Bold(true)
	}
	if strings.Contains(str, "reverse") {
		style = style.Reverse(true)
	}
	if strings.Contains(str, "underline") {
		style = style.Underline(true)
	}
	return style
}

// StringToColor returns a tcell color from a string representation of a color
// We accept either bright... or light... to mean the brighter version of a color
func StringToColor(str string) tcell.Color {
	switch str {
	case "black":
		return tcell.ColorBlack
	case "red":
		return tcell.ColorMaroon
	case "green":
		return tcell.ColorGreen
	case "yellow":
		return tcell.ColorOlive
	case "blue":
		return tcell.ColorNavy
	case "magenta":
		return tcell.ColorPurple
	case "cyan":
		return tcell.ColorTeal
	case "white":
		return tcell.ColorSilver
	case "brightblack", "lightblack":
		return tcell.ColorGray
	case "brightred", "lightred":
		return tcell.ColorRed
	case "brightgreen", "lightgreen":
		return tcell.ColorLime
	case "brightyellow", "lightyellow":
		return tcell.ColorYellow
	case "brightblue", "lightblue":
		return tcell.ColorBlue
	case "brightmagenta", "lightmagenta":
		return tcell.ColorFuchsia
	case "brightcyan", "lightcyan":
		return tcell.ColorAqua
	case "brightwhite", "lightwhite":
		return tcell.ColorWhite
	case "default":
		return tcell.ColorDefault
	default:
		// Check if this is a 256 color
		if num, err := strconv.Atoi(str); err == nil {
			return GetColor256(num)
		}
		// Probably a truecolor hex value
		return tcell.GetColor(str)
	}
}

// GetColor256 returns the tcell color for a number between 0 and 255
func GetColor256(color int) tcell.Color {
	ansiColors := []tcell.Color{tcell.ColorBlack, tcell.ColorMaroon, tcell.ColorGreen,
		tcell.ColorOlive, tcell.ColorNavy, tcell.ColorPurple,
		tcell.ColorTeal, tcell.ColorSilver, tcell.ColorGray,
		tcell.ColorRed, tcell.ColorLime, tcell.ColorYellow,
		tcell.ColorBlue, tcell.ColorFuchsia, tcell.ColorAqua,
		tcell.ColorWhite}

	if color >= 0 && color <= 15 {
		return ansiColors[color]
	}

	return tcell.GetColor("Color" + strconv.Itoa(color))
}
<commit_msg>Fix homedir more<commit_after>package main

import (
	"fmt"
	"github.com/gdamore/tcell"
	"github.com/mitchellh/go-homedir"
	"io/ioutil"
	"os/user"
	"regexp"
	"strconv"
	"strings"
)

const defaultColorscheme = "default"

// Colorscheme is a map from string to style -- it represents a colorscheme
type Colorscheme map[string]tcell.Style

// The current colorscheme
var colorscheme Colorscheme

// InitColorscheme picks and initializes the colorscheme when micro starts
func InitColorscheme() {
	LoadDefaultColorscheme()
}

// LoadDefaultColorscheme loads the default colorscheme from ~/.micro/colorschemes
func LoadDefaultColorscheme() {
	dir, err := homedir.Dir()
	if err != nil {
		TermMessage("Error finding your home directory\nCan't load runtime files")
		return
	}
	LoadColorscheme(defaultColorscheme, dir+"/.micro/colorschemes")
}

// LoadColorscheme loads the given colorscheme from a directory
func LoadColorscheme(colorschemeName, dir string) {
	files, _ := ioutil.ReadDir(dir)
	for _, f := range files {
		if f.Name() == colorschemeName+".micro" {
			text, err := ioutil.ReadFile(dir + "/" + f.Name())
			if err != nil {
				fmt.Println("Error loading colorscheme:", err)
				continue
			}
			colorscheme = ParseColorscheme(string(text))
		}
	}
}

// ParseColorscheme parses the text definition for a colorscheme and returns the corresponding object
// Colorschemes are made up of color-link statements linking a color group to a list of colors
// For example, color-link keyword (blue,red) makes all keywords have a blue foreground and
// red background
func ParseColorscheme(text string) Colorscheme {
	parser := regexp.MustCompile(`color-link\s+(\S*)\s+"(.*)"`)

	lines := strings.Split(text, "\n")

	c := make(Colorscheme)

	for _, line := range lines {
		if strings.TrimSpace(line) == "" ||
			strings.TrimSpace(line)[0] == '#' {
			// Ignore this line
			continue
		}

		matches := parser.FindSubmatch([]byte(line))
		if len(matches) == 3 {
			link := string(matches[1])
			colors := string(matches[2])

			c[link] = StringToStyle(colors)
		} else {
			fmt.Println("Color-link statement is not valid:", line)
		}
	}

	return c
}

// StringToStyle returns a style from a string
// The strings must be in the format "extra foregroundcolor,backgroundcolor"
// The 'extra' can be bold, reverse, or underline
func StringToStyle(str string) tcell.Style {
	var fg string
	var bg string
	split := strings.Split(str, ",")
	if len(split) > 1 {
		fg, bg = split[0], split[1]
	} else {
		fg = split[0]
	}
	fg = strings.TrimSpace(fg)
	bg = strings.TrimSpace(bg)

	style := tcell.StyleDefault.Foreground(StringToColor(fg)).Background(StringToColor(bg))
	if strings.Contains(str, "bold") {
		style = style.Bold(true)
	}
	if strings.Contains(str, "reverse") {
		style = style.Reverse(true)
	}
	if strings.Contains(str, "underline") {
		style = style.Underline(true)
	}
	return style
}

// StringToColor returns a tcell color from a string representation of a color
// We accept either bright... or light... to mean the brighter version of a color
func StringToColor(str string) tcell.Color {
	switch str {
	case "black":
		return tcell.ColorBlack
	case "red":
		return tcell.ColorMaroon
	case "green":
		return tcell.ColorGreen
	case "yellow":
		return tcell.ColorOlive
	case "blue":
		return tcell.ColorNavy
	case "magenta":
		return tcell.ColorPurple
	case "cyan":
		return tcell.ColorTeal
	case "white":
		return tcell.ColorSilver
	case "brightblack", "lightblack":
		return tcell.ColorGray
	case "brightred", "lightred":
		return tcell.ColorRed
	case "brightgreen", "lightgreen":
		return tcell.ColorLime
	case "brightyellow", "lightyellow":
		return tcell.ColorYellow
	case "brightblue", "lightblue":
		return tcell.ColorBlue
	case "brightmagenta", "lightmagenta":
		return tcell.ColorFuchsia
	case "brightcyan", "lightcyan":
		return tcell.ColorAqua
	case "brightwhite", "lightwhite":
		return tcell.ColorWhite
	case "default":
		return tcell.ColorDefault
	default:
		// Check if this is a 256 color
		if num, err := strconv.Atoi(str); err == nil {
			return GetColor256(num)
		}
		// Probably a truecolor hex value
		return tcell.GetColor(str)
	}
}

// GetColor256 returns the tcell color for a number between 0 and 255
func GetColor256(color int) tcell.Color {
	ansiColors := []tcell.Color{tcell.ColorBlack, tcell.ColorMaroon, tcell.ColorGreen,
		tcell.ColorOlive, tcell.ColorNavy, tcell.ColorPurple,
		tcell.ColorTeal, tcell.ColorSilver, tcell.ColorGray,
		tcell.ColorRed, tcell.ColorLime, tcell.ColorYellow,
		tcell.ColorBlue, tcell.ColorFuchsia, tcell.ColorAqua,
		tcell.ColorWhite}

	if color >= 0 && color <= 15 {
		return ansiColors[color]
	}

	return tcell.GetColor("Color" + strconv.Itoa(color))
}
<|endoftext|>


<commit_before>package interfaces

import "cjdavis.me/elysium/models"

type BookRepository interface {
	GetAllBooks() ([]models.Book, error)
	GetBooksByAuthor(authorID int) ([]models.Book, error)
}
<commit_msg>Correct book repoistory interface name<commit_after>package interfaces

import "cjdavis.me/elysium/models"

type IBookRepository interface {
	GetAllBooks() ([]models.Book, error)
	GetBooksByAuthor(authorID int) ([]models.Book, error)
}
<|endoftext|>


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

package libkbfs

import (
	"path/filepath"
	"sync"

	"github.com/keybase/kbfs/kbfsblock"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/keybase/kbfs/kbfsmd"
	"github.com/keybase/kbfs/kbfssync"
	"github.com/keybase/kbfs/tlf"
	"github.com/pkg/errors"
	ldberrors "github.com/syndtr/goleveldb/leveldb/errors"
	"golang.org/x/net/context"
)

const (
	workingSetCacheFolderName = "kbfs_block_cache"
	syncCacheFolderName       = "kbfs_sync_cache"
)

// diskBlockCacheConfig specifies the interfaces that a DiskBlockCacheStandard
// needs to perform its functions. This adheres to the standard libkbfs Config
// API.
type diskBlockCacheConfig interface {
	codecGetter
	logMaker
	clockGetter
	diskLimiterGetter
	initModeGetter
}

type diskBlockCacheWrapped struct {
	config      diskBlockCacheConfig
	storageRoot string
	// Protects the caches
	mtx             sync.RWMutex
	workingSetCache *DiskBlockCacheLocal
	syncCache       *DiskBlockCacheLocal
	deleteGroup     kbfssync.RepeatedWaitGroup
}

var _ DiskBlockCache = (*diskBlockCacheWrapped)(nil)

func (cache *diskBlockCacheWrapped) enableCache(
	typ diskLimitTrackerType, cacheFolder string) (err error) {
	cache.mtx.Lock()
	defer cache.mtx.Unlock()
	var cachePtr **DiskBlockCacheLocal
	switch typ {
	case syncCacheLimitTrackerType:
		cachePtr = &cache.syncCache
	case workingSetCacheLimitTrackerType:
		cachePtr = &cache.workingSetCache
	default:
		return errors.New("invalid disk cache type")
	}
	if *cachePtr != nil {
		// We already have a cache of the desired type. Thus, this method is
		// idempotent.
		return nil
	}
	if cache.config.IsTestMode() {
		*cachePtr, err = newDiskBlockCacheLocalForTest(
			cache.config, typ)
	} else {
		cacheStorageRoot := filepath.Join(cache.storageRoot, cacheFolder)
		*cachePtr, err = newDiskBlockCacheLocal(cache.config, typ,
			cacheStorageRoot)
	}
	return err
}

func newDiskBlockCacheWrapped(config diskBlockCacheConfig,
	storageRoot string) (cache *diskBlockCacheWrapped, err error) {
	cache = &diskBlockCacheWrapped{
		config:      config,
		storageRoot: storageRoot,
	}
	err = cache.enableCache(workingSetCacheLimitTrackerType,
		workingSetCacheFolderName)
	if err != nil {
		return nil, err
	}
	syncCacheErr := cache.enableCache(syncCacheLimitTrackerType,
		syncCacheFolderName)
	if syncCacheErr != nil {
		log := config.MakeLogger("DBC")
		log.Warning("Could not initialize sync block cache.")
		// We still return success because the working set cache successfully
		// initialized.
	}
	return cache, nil
}

// DoesSyncCacheHaveSpace returns true if we have more than 1% of space left in
// the sync cache.
func (cache *diskBlockCacheWrapped) DoesSyncCacheHaveSpace(
	ctx context.Context) bool {
	if !cache.IsSyncCacheEnabled() {
		return false
	}
	return cache.syncCache.DoesSyncCacheHaveSpace(ctx)
}

// IsSyncCacheEnabled returns true if the sync cache is enabled.
func (cache *diskBlockCacheWrapped) IsSyncCacheEnabled() bool {
	return cache.syncCache != nil
}

// Get implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Get(
	ctx context.Context, tlfID tlf.ID, blockID kbfsblock.ID,
	preferredCacheType DiskBlockCacheType) (
	buf []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	prefetchStatus PrefetchStatus, err error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	primaryCache := cache.workingSetCache
	secondaryCache := cache.syncCache
	if preferredCacheType == DiskBlockSyncCache {
		if cache.syncCache != nil {
			primaryCache, secondaryCache = secondaryCache, primaryCache
		} else {
			log := cache.config.MakeLogger("DBC")
			log.Warning("Sync cache is preferred, but there is no sync cache")
		}
	}
	// Check both caches if the primary cache doesn't have the block.
	buf, serverHalf, prefetchStatus, err =
		primaryCache.Get(ctx, tlfID, blockID, preferredCacheType)
	if _, isNoSuchBlockError := err.(NoSuchBlockError); isNoSuchBlockError &&
		secondaryCache != nil {
		buf, serverHalf, prefetchStatus, err = secondaryCache.Get(
			ctx, tlfID, blockID, preferredCacheType)
		if err != nil {
			return nil, kbfscrypto.BlockCryptKeyServerHalf{}, NoPrefetch, err
		}
		if preferredCacheType != DiskBlockAnyCache {
			// Move the block into its preferred cache.
			err := primaryCache.Put(
				ctx, tlfID, blockID, buf, serverHalf, preferredCacheType)
			if err != nil {
				// The cache will log the non-fatal error, so just return nil.
				return buf, serverHalf, prefetchStatus, nil
			}
			err = primaryCache.UpdateMetadata(ctx, blockID, prefetchStatus)
			if err != nil {
				// The cache will log the non-fatal error, so just return nil.
				return buf, serverHalf, prefetchStatus, nil
			}
			cache.deleteGroup.Add(1)
			go func() {
				defer cache.deleteGroup.Done()
				secondaryCache.Delete(ctx, []kbfsblock.ID{blockID})
			}()
		}
	}
	return buf, serverHalf, prefetchStatus, err
}

// GetMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetMetadata(ctx context.Context,
	blockID kbfsblock.ID) (metadata DiskBlockCacheMetadata, err error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache != nil {
		md, err := cache.syncCache.GetMetadata(ctx, blockID)
		switch errors.Cause(err) {
		case nil:
			return md, nil
		case ldberrors.ErrNotFound:
		default:
			return md, err
		}
	}
	return cache.workingSetCache.GetMetadata(ctx, blockID)
}

// Put implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Put(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID, buf []byte,
	serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	cacheType DiskBlockCacheType) error {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cacheType == DiskBlockSyncCache && cache.syncCache != nil {
		workingSetCache := cache.workingSetCache
		err := cache.syncCache.Put(
			ctx, tlfID, blockID, buf, serverHalf, cacheType)
		if err == nil {
			cache.deleteGroup.Add(1)
			go func() {
				defer cache.deleteGroup.Done()
				workingSetCache.Delete(ctx, []kbfsblock.ID{blockID})
			}()
			return nil
		}
		// Otherwise drop through and put it into the working set cache.
	}
	// TODO: Allow more intelligent transitioning from the sync cache to
	// the working set cache.
	if cache.syncCache != nil {
		syncCache := cache.syncCache
		cache.deleteGroup.Add(1)
		go func() {
			defer cache.deleteGroup.Done()
			syncCache.Delete(ctx, []kbfsblock.ID{blockID})
		}()
	}
	return cache.workingSetCache.Put(
		ctx, tlfID, blockID, buf, serverHalf, cacheType)
}

// Delete implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Delete(ctx context.Context,
	blockIDs []kbfsblock.ID) (numRemoved int, sizeRemoved int64, err error) {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	numRemoved, sizeRemoved, err = cache.workingSetCache.Delete(ctx, blockIDs)
	if cache.syncCache == nil || err != nil {
		return numRemoved, sizeRemoved, err
	}
	syncNumRemoved, syncSizeRemoved, err :=
		cache.syncCache.Delete(ctx, blockIDs)
	return numRemoved + syncNumRemoved, sizeRemoved + syncSizeRemoved, err
}

// UpdateMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) UpdateMetadata(ctx context.Context,
	blockID kbfsblock.ID, prefetchStatus PrefetchStatus) error {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	// Try to update metadata for both caches.
	if cache.syncCache != nil {
		err := cache.syncCache.UpdateMetadata(ctx, blockID, prefetchStatus)
		_, isNoSuchBlockError := err.(NoSuchBlockError)
		if !isNoSuchBlockError {
			return err
		}
	}
	return cache.workingSetCache.UpdateMetadata(ctx, blockID, prefetchStatus)
}

// ClearAllTlfBlocks implements the DiskBlockCache interface for
// diskBlockCacheWrapper.
func (cache *diskBlockCacheWrapped) ClearAllTlfBlocks(
	ctx context.Context, tlfID tlf.ID) error {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	// We only clear blocks from the sync cache.
	if cache.syncCache == nil {
		return nil
	}
	return cache.syncCache.ClearAllTlfBlocks(ctx, tlfID)
}

// GetLastUnrefRev implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetLastUnrefRev(
	ctx context.Context, tlfID tlf.ID) (kbfsmd.Revision, error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache == nil {
		return kbfsmd.RevisionUninitialized,
			errors.New("Sync cache not enabled")
	}
	return cache.syncCache.GetLastUnrefRev(ctx, tlfID)
}

// PutLastUnrefRev implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) PutLastUnrefRev(
	ctx context.Context, tlfID tlf.ID, rev kbfsmd.Revision) error {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache == nil {
		return errors.New("Sync cache not enabled")
	}
	return cache.syncCache.PutLastUnrefRev(ctx, tlfID, rev)
}

// Status implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Status(
	ctx context.Context) map[string]DiskBlockCacheStatus {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	statuses := make(map[string]DiskBlockCacheStatus, 2)
	if cache.workingSetCache != nil {
		for name, status := range cache.workingSetCache.Status(ctx) {
			statuses[name] = status
		}
	}
	if cache.syncCache == nil {
		return statuses
	}
	for name, status := range cache.syncCache.Status(ctx) {
		statuses[name] = status
	}
	return statuses
}

func (cache *diskBlockCacheWrapped) waitForDeletes(ctx context.Context) error {
	return cache.deleteGroup.Wait(ctx)
}

// Shutdown implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Shutdown(ctx context.Context) {
	cache.mtx.Lock()
	defer cache.mtx.Unlock()
	cache.workingSetCache.Shutdown(ctx)
	if cache.syncCache != nil {
		cache.syncCache.Shutdown(ctx)
	}
}
<commit_msg>disk_block_cache_wrapped: some suggested clarifications<commit_after>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"path/filepath"
	"sync"

	"github.com/keybase/kbfs/kbfsblock"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/keybase/kbfs/kbfsmd"
	"github.com/keybase/kbfs/kbfssync"
	"github.com/keybase/kbfs/tlf"
	"github.com/pkg/errors"
	ldberrors "github.com/syndtr/goleveldb/leveldb/errors"
	"golang.org/x/net/context"
)

const (
	workingSetCacheFolderName = "kbfs_block_cache"
	syncCacheFolderName       = "kbfs_sync_cache"
)

// diskBlockCacheConfig specifies the interfaces that a DiskBlockCacheStandard
// needs to perform its functions. This adheres to the standard libkbfs Config
// API.
type diskBlockCacheConfig interface {
	codecGetter
	logMaker
	clockGetter
	diskLimiterGetter
	initModeGetter
}

type diskBlockCacheWrapped struct {
	config      diskBlockCacheConfig
	storageRoot string
	// Protects the caches
	mtx             sync.RWMutex
	workingSetCache *DiskBlockCacheLocal
	syncCache       *DiskBlockCacheLocal
	deleteGroup     kbfssync.RepeatedWaitGroup
}

var _ DiskBlockCache = (*diskBlockCacheWrapped)(nil)

func (cache *diskBlockCacheWrapped) enableCache(
	typ diskLimitTrackerType, cacheFolder string) (err error) {
	cache.mtx.Lock()
	defer cache.mtx.Unlock()
	var cachePtr **DiskBlockCacheLocal
	switch typ {
	case syncCacheLimitTrackerType:
		cachePtr = &cache.syncCache
	case workingSetCacheLimitTrackerType:
		cachePtr = &cache.workingSetCache
	default:
		return errors.New("invalid disk cache type")
	}
	if *cachePtr != nil {
		// We already have a cache of the desired type. Thus, this method is
		// idempotent.
		return nil
	}
	if cache.config.IsTestMode() {
		*cachePtr, err = newDiskBlockCacheLocalForTest(
			cache.config, typ)
	} else {
		cacheStorageRoot := filepath.Join(cache.storageRoot, cacheFolder)
		*cachePtr, err = newDiskBlockCacheLocal(cache.config, typ,
			cacheStorageRoot)
	}
	return err
}

func newDiskBlockCacheWrapped(config diskBlockCacheConfig,
	storageRoot string) (cache *diskBlockCacheWrapped, err error) {
	cache = &diskBlockCacheWrapped{
		config:      config,
		storageRoot: storageRoot,
	}
	err = cache.enableCache(workingSetCacheLimitTrackerType,
		workingSetCacheFolderName)
	if err != nil {
		return nil, err
	}
	syncCacheErr := cache.enableCache(syncCacheLimitTrackerType,
		syncCacheFolderName)
	if syncCacheErr != nil {
		log := config.MakeLogger("DBC")
		log.Warning("Could not initialize sync block cache.")
		// We still return success because the working set cache successfully
		// initialized.
	}
	return cache, nil
}

// DoesSyncCacheHaveSpace returns true if we have more than 1% of space left in
// the sync cache.
func (cache *diskBlockCacheWrapped) DoesSyncCacheHaveSpace(
	ctx context.Context) bool {
	if !cache.IsSyncCacheEnabled() {
		return false
	}
	return cache.syncCache.DoesSyncCacheHaveSpace(ctx)
}

// IsSyncCacheEnabled returns true if the sync cache is enabled.
func (cache *diskBlockCacheWrapped) IsSyncCacheEnabled() bool {
	return cache.syncCache != nil
}

// Get implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Get(
	ctx context.Context, tlfID tlf.ID, blockID kbfsblock.ID,
	preferredCacheType DiskBlockCacheType) (
	buf []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	prefetchStatus PrefetchStatus, err error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	primaryCache := cache.workingSetCache
	secondaryCache := cache.syncCache
	if preferredCacheType == DiskBlockSyncCache {
		if cache.syncCache != nil {
			primaryCache, secondaryCache =
				cache.syncCache, cache.workingSetCache
		} else {
			log := cache.config.MakeLogger("DBC")
			log.Warning("Sync cache is preferred, but there is no sync cache")
		}
	}
	// Check both caches if the primary cache doesn't have the block.
	buf, serverHalf, prefetchStatus, err =
		primaryCache.Get(ctx, tlfID, blockID, preferredCacheType)
	if _, isNoSuchBlockError := err.(NoSuchBlockError); isNoSuchBlockError &&
		secondaryCache != nil {
		buf, serverHalf, prefetchStatus, err = secondaryCache.Get(
			ctx, tlfID, blockID, preferredCacheType)
		if err != nil {
			return nil, kbfscrypto.BlockCryptKeyServerHalf{}, NoPrefetch, err
		}
		if preferredCacheType != DiskBlockAnyCache {
			// Move the block into its preferred cache.
			err := primaryCache.Put(
				ctx, tlfID, blockID, buf, serverHalf, preferredCacheType)
			if err != nil {
				// The cache will log the non-fatal error, so just return nil.
				return buf, serverHalf, prefetchStatus, nil
			}
			err = primaryCache.UpdateMetadata(ctx, blockID, prefetchStatus)
			if err != nil {
				// The cache will log the non-fatal error, so just return nil.
				return buf, serverHalf, prefetchStatus, nil
			}
			// Remove the block from the non-preferred cache (which is
			// set to be the secondary cache at this point).
			cache.deleteGroup.Add(1)
			go func() {
				defer cache.deleteGroup.Done()
				secondaryCache.Delete(ctx, []kbfsblock.ID{blockID})
			}()
		}
	}
	return buf, serverHalf, prefetchStatus, err
}

// GetMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetMetadata(ctx context.Context,
	blockID kbfsblock.ID) (metadata DiskBlockCacheMetadata, err error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache != nil {
		md, err := cache.syncCache.GetMetadata(ctx, blockID)
		switch errors.Cause(err) {
		case nil:
			return md, nil
		case ldberrors.ErrNotFound:
		default:
			return md, err
		}
	}
	return cache.workingSetCache.GetMetadata(ctx, blockID)
}

// Put implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Put(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID, buf []byte,
	serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	cacheType DiskBlockCacheType) error {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cacheType == DiskBlockSyncCache && cache.syncCache != nil {
		workingSetCache := cache.workingSetCache
		err := cache.syncCache.Put(
			ctx, tlfID, blockID, buf, serverHalf, cacheType)
		if err == nil {
			cache.deleteGroup.Add(1)
			go func() {
				defer cache.deleteGroup.Done()
				workingSetCache.Delete(ctx, []kbfsblock.ID{blockID})
			}()
			return nil
		}
		// Otherwise drop through and put it into the working set cache.
	}
	// TODO: Allow more intelligent transitioning from the sync cache to
	// the working set cache.
	if cache.syncCache != nil {
		syncCache := cache.syncCache
		cache.deleteGroup.Add(1)
		go func() {
			defer cache.deleteGroup.Done()
			syncCache.Delete(ctx, []kbfsblock.ID{blockID})
		}()
	}
	return cache.workingSetCache.Put(
		ctx, tlfID, blockID, buf, serverHalf, cacheType)
}

// Delete implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Delete(ctx context.Context,
	blockIDs []kbfsblock.ID) (numRemoved int, sizeRemoved int64, err error) {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	numRemoved, sizeRemoved, err = cache.workingSetCache.Delete(ctx, blockIDs)
	if cache.syncCache == nil || err != nil {
		return numRemoved, sizeRemoved, err
	}
	syncNumRemoved, syncSizeRemoved, err :=
		cache.syncCache.Delete(ctx, blockIDs)
	return numRemoved + syncNumRemoved, sizeRemoved + syncSizeRemoved, err
}

// UpdateMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) UpdateMetadata(ctx context.Context,
	blockID kbfsblock.ID, prefetchStatus PrefetchStatus) error {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	// Try to update metadata for both caches.
	if cache.syncCache != nil {
		err := cache.syncCache.UpdateMetadata(ctx, blockID, prefetchStatus)
		_, isNoSuchBlockError := err.(NoSuchBlockError)
		if !isNoSuchBlockError {
			return err
		}
	}
	return cache.workingSetCache.UpdateMetadata(ctx, blockID, prefetchStatus)
}

// ClearAllTlfBlocks implements the DiskBlockCache interface for
// diskBlockCacheWrapper.
func (cache *diskBlockCacheWrapped) ClearAllTlfBlocks(
	ctx context.Context, tlfID tlf.ID) error {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	// We only clear blocks from the sync cache.
	if cache.syncCache == nil {
		return nil
	}
	return cache.syncCache.ClearAllTlfBlocks(ctx, tlfID)
}

// GetLastUnrefRev implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetLastUnrefRev(
	ctx context.Context, tlfID tlf.ID) (kbfsmd.Revision, error) {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache == nil {
		return kbfsmd.RevisionUninitialized,
			errors.New("Sync cache not enabled")
	}
	return cache.syncCache.GetLastUnrefRev(ctx, tlfID)
}

// PutLastUnrefRev implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) PutLastUnrefRev(
	ctx context.Context, tlfID tlf.ID, rev kbfsmd.Revision) error {
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	if cache.syncCache == nil {
		return errors.New("Sync cache not enabled")
	}
	return cache.syncCache.PutLastUnrefRev(ctx, tlfID, rev)
}

// Status implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Status(
	ctx context.Context) map[string]DiskBlockCacheStatus {
	// This is a write operation but we are only reading the pointers to the
	// caches. So we use a read lock.
	cache.mtx.RLock()
	defer cache.mtx.RUnlock()
	statuses := make(map[string]DiskBlockCacheStatus, 2)
	if cache.workingSetCache != nil {
		for name, status := range cache.workingSetCache.Status(ctx) {
			statuses[name] = status
		}
	}
	if cache.syncCache == nil {
		return statuses
	}
	for name, status := range cache.syncCache.Status(ctx) {
		statuses[name] = status
	}
	return statuses
}

func (cache *diskBlockCacheWrapped) waitForDeletes(ctx context.Context) error {
	return cache.deleteGroup.Wait(ctx)
}

// Shutdown implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Shutdown(ctx context.Context) {
	cache.mtx.Lock()
	defer cache.mtx.Unlock()
	cache.workingSetCache.Shutdown(ctx)
	if cache.syncCache != nil {
		cache.syncCache.Shutdown(ctx)
	}
}
<|endoftext|>


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

package libkbfs

import (
	"path/filepath"

	"golang.org/x/net/context"

	"github.com/keybase/kbfs/kbfsblock"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/keybase/kbfs/tlf"
	"github.com/syndtr/goleveldb/leveldb/errors"
)

const (
	workingSetCacheFolderName = "kbfs_block_cache"
	syncCacheFolderName       = "kbfs_sync_cache"
)

// diskBlockCacheConfig specifies the interfaces that a DiskBlockCacheStandard
// needs to perform its functions. This adheres to the standard libkbfs Config
// API.
type diskBlockCacheConfig interface {
	codecGetter
	logMaker
	clockGetter
	diskLimiterGetter
	syncedTlfGetterSetter
}

type diskBlockCacheWrapped struct {
	config          diskBlockCacheConfig
	workingSetCache DiskBlockCache
	syncCache       DiskBlockCache
}

var _ DiskBlockCache = (*diskBlockCacheWrapped)(nil)

func newDiskBlockCacheWrapped(config diskBlockCacheConfig, storageRoot string) (
	cache *diskBlockCacheWrapped, err error) {
	workingSetCacheRoot := filepath.Join(storageRoot, workingSetCacheFolderName)
	workingSetCache, err := newDiskBlockCacheStandard(config, false,
		workingSetCacheRoot)
	if err != nil {
		return nil, err
	}
	return &diskBlockCacheWrapped{
		config:          config,
		workingSetCache: workingSetCache,
		syncCache:       nil,
	}, nil
}

// Get implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Get(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID) (
	buf []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	hasPrefetched bool, err error) {
	// TODO: add mutex to guard sync state
	primaryCache := cache.workingSetCache
	secondaryCache := cache.syncCache
	if cache.config.IsSyncedTlf(tlfID) {
		primaryCache = cache.syncCache
		secondaryCache = cache.workingSetCache
	}
	// Check both caches if the primary cache doesn't have the block.
	buf, serverHalf, hasPrefetched, err = primaryCache.Get(ctx, tlfID, blockID)
	if _, isNoSuchBlockError := err.(NoSuchBlockError); isNoSuchBlockError {
		return secondaryCache.Get(ctx, tlfID, blockID)
	}
	return buf, serverHalf, hasPrefetched, err
}

// GetMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetMetadata(ctx context.Context,
	blockID kbfsblock.ID) (metadata DiskBlockCacheMetadata, err error) {
	// TODO: add mutex to guard sync state
	if cache.syncCache != nil {
		md, err := cache.syncCache.GetMetadata(ctx, blockID)
		switch err {
		case nil:
			return md, nil
		case errors.ErrNotFound:
		default:
			return md, err
		}
	}
	return cache.workingSetCache.GetMetadata(ctx, blockID)
}

// Put implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Put(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID, buf []byte,
	serverHalf kbfscrypto.BlockCryptKeyServerHalf) error {
	if cache.config.IsSyncedTlf(tlfID) {
		cache.workingSetCache.Delete(ctx, []kbfsblock.ID{blockID})
		return cache.syncCache.Put(ctx, tlfID, blockID, buf, serverHalf)
	}
	// TODO: Allow more intelligent transitioning from the sync cache to
	// the working set cache.
	cache.syncCache.Delete(ctx, []kbfsblock.ID{blockID})
	return cache.workingSetCache.Put(ctx, tlfID, blockID, buf, serverHalf)
}

// Delete implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Delete(ctx context.Context,
	blockIDs []kbfsblock.ID) (numRemoved int, sizeRemoved int64, err error) {
	numRemoved, sizeRemoved, err = cache.workingSetCache.Delete(ctx, blockIDs)
	if cache.syncCache == nil || err != nil {
		return numRemoved, sizeRemoved, err
	}
	syncNumRemoved, syncSizeRemoved, err :=
		cache.syncCache.Delete(ctx, blockIDs)
	return numRemoved + syncNumRemoved, sizeRemoved + syncSizeRemoved, err
}

// UpdateMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) UpdateMetadata(ctx context.Context,
	blockID kbfsblock.ID, hasPrefetched, donePrefetch bool) error {
	// Try to update metadata for both caches.
	if cache.syncCache != nil {
		err := cache.syncCache.UpdateMetadata(ctx, blockID, hasPrefetched,
			donePrefetch)
		_, isNoSuchBlockError := err.(NoSuchBlockError)
		if !isNoSuchBlockError {
			return err
		}
	}
	return cache.workingSetCache.UpdateMetadata(ctx, blockID, hasPrefetched,
		donePrefetch)
}

// Size implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Size() int64 {
	size := cache.workingSetCache.Size()
	if cache.syncCache != nil {
		size += cache.syncCache.Size()
	}
	return size
}

// Status implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Status(
	ctx context.Context) *DiskBlockCacheStatus {
	// TODO: include syncCache
	return cache.workingSetCache.Status(ctx)
}

// Shutdown implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Shutdown(ctx context.Context) {
	cache.workingSetCache.Shutdown(ctx)
	if cache.syncCache != nil {
		cache.syncCache.Shutdown(ctx)
	}
}
<commit_msg>disk_block_cache: Fix panics due to nils<commit_after>// Copyright 2017 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"path/filepath"

	"golang.org/x/net/context"

	"github.com/keybase/kbfs/kbfsblock"
	"github.com/keybase/kbfs/kbfscrypto"
	"github.com/keybase/kbfs/tlf"
	"github.com/syndtr/goleveldb/leveldb/errors"
)

const (
	workingSetCacheFolderName = "kbfs_block_cache"
	syncCacheFolderName       = "kbfs_sync_cache"
)

// diskBlockCacheConfig specifies the interfaces that a DiskBlockCacheStandard
// needs to perform its functions. This adheres to the standard libkbfs Config
// API.
type diskBlockCacheConfig interface {
	codecGetter
	logMaker
	clockGetter
	diskLimiterGetter
	syncedTlfGetterSetter
}

type diskBlockCacheWrapped struct {
	config          diskBlockCacheConfig
	workingSetCache DiskBlockCache
	syncCache       DiskBlockCache
}

var _ DiskBlockCache = (*diskBlockCacheWrapped)(nil)

func newDiskBlockCacheWrapped(config diskBlockCacheConfig, storageRoot string) (
	cache *diskBlockCacheWrapped, err error) {
	workingSetCacheRoot := filepath.Join(storageRoot, workingSetCacheFolderName)
	workingSetCache, err := newDiskBlockCacheStandard(config, false,
		workingSetCacheRoot)
	if err != nil {
		return nil, err
	}
	return &diskBlockCacheWrapped{
		config:          config,
		workingSetCache: workingSetCache,
		syncCache:       nil,
	}, nil
}

// Get implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Get(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID) (
	buf []byte, serverHalf kbfscrypto.BlockCryptKeyServerHalf,
	hasPrefetched bool, err error) {
	// TODO: add mutex to guard sync state
	primaryCache := cache.workingSetCache
	secondaryCache := cache.syncCache
	if cache.config.IsSyncedTlf(tlfID) {
		primaryCache = cache.syncCache
		secondaryCache = cache.workingSetCache
	}
	// Check both caches if the primary cache doesn't have the block.
	buf, serverHalf, hasPrefetched, err = primaryCache.Get(ctx, tlfID, blockID)
	if _, isNoSuchBlockError := err.(NoSuchBlockError); isNoSuchBlockError {
		if secondaryCache != nil {
			return secondaryCache.Get(ctx, tlfID, blockID)
		}
	}
	return buf, serverHalf, hasPrefetched, err
}

// GetMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) GetMetadata(ctx context.Context,
	blockID kbfsblock.ID) (metadata DiskBlockCacheMetadata, err error) {
	// TODO: add mutex to guard sync state
	if cache.syncCache != nil {
		md, err := cache.syncCache.GetMetadata(ctx, blockID)
		switch err {
		case nil:
			return md, nil
		case errors.ErrNotFound:
		default:
			return md, err
		}
	}
	return cache.workingSetCache.GetMetadata(ctx, blockID)
}

// Put implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Put(ctx context.Context, tlfID tlf.ID,
	blockID kbfsblock.ID, buf []byte,
	serverHalf kbfscrypto.BlockCryptKeyServerHalf) error {
	if cache.config.IsSyncedTlf(tlfID) {
		cache.workingSetCache.Delete(ctx, []kbfsblock.ID{blockID})
		return cache.syncCache.Put(ctx, tlfID, blockID, buf, serverHalf)
	}
	// TODO: Allow more intelligent transitioning from the sync cache to
	// the working set cache.
	if cache.syncCache != nil {
		cache.syncCache.Delete(ctx, []kbfsblock.ID{blockID})
	}
	return cache.workingSetCache.Put(ctx, tlfID, blockID, buf, serverHalf)
}

// Delete implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Delete(ctx context.Context,
	blockIDs []kbfsblock.ID) (numRemoved int, sizeRemoved int64, err error) {
	numRemoved, sizeRemoved, err = cache.workingSetCache.Delete(ctx, blockIDs)
	if cache.syncCache == nil || err != nil {
		return numRemoved, sizeRemoved, err
	}
	syncNumRemoved, syncSizeRemoved, err :=
		cache.syncCache.Delete(ctx, blockIDs)
	return numRemoved + syncNumRemoved, sizeRemoved + syncSizeRemoved, err
}

// UpdateMetadata implements the DiskBlockCache interface for
// diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) UpdateMetadata(ctx context.Context,
	blockID kbfsblock.ID, hasPrefetched, donePrefetch bool) error {
	// Try to update metadata for both caches.
	if cache.syncCache != nil {
		err := cache.syncCache.UpdateMetadata(ctx, blockID, hasPrefetched,
			donePrefetch)
		_, isNoSuchBlockError := err.(NoSuchBlockError)
		if !isNoSuchBlockError {
			return err
		}
	}
	return cache.workingSetCache.UpdateMetadata(ctx, blockID, hasPrefetched,
		donePrefetch)
}

// Size implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Size() int64 {
	size := cache.workingSetCache.Size()
	if cache.syncCache != nil {
		size += cache.syncCache.Size()
	}
	return size
}

// Status implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Status(
	ctx context.Context) *DiskBlockCacheStatus {
	// TODO: include syncCache
	return cache.workingSetCache.Status(ctx)
}

// Shutdown implements the DiskBlockCache interface for diskBlockCacheWrapped.
func (cache *diskBlockCacheWrapped) Shutdown(ctx context.Context) {
	cache.workingSetCache.Shutdown(ctx)
	if cache.syncCache != nil {
		cache.syncCache.Shutdown(ctx)
	}
}
<|endoftext|>


<commit_before>package middleware

import (
	"net/http"
	"net/http/httptest"
	"runtime"
	"strings"
	"testing"

	"github.com/docker/docker/api/server/httputils"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

func TestVersionMiddleware(t *testing.T) {
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		if httputils.VersionFromContext(ctx) == "" {
			t.Fatal("Expected version, got empty string")
		}
		return nil
	}

	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()
	if err := h(ctx, resp, req, map[string]string{}); err != nil {
		t.Fatal(err)
	}
}

func TestVersionMiddlewareVersionTooOld(t *testing.T) {
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		if httputils.VersionFromContext(ctx) == "" {
			t.Fatal("Expected version, got empty string")
		}
		return nil
	}

	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()

	vars := map[string]string{"version": "0.1"}
	err := h(ctx, resp, req, vars)

	if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") {
		t.Fatalf("Expected too old client error, got %v", err)
	}
}

func TestVersionMiddlewareVersionTooNew(t *testing.T) {
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		if httputils.VersionFromContext(ctx) == "" {
			t.Fatal("Expected version, got empty string")
		}
		return nil
	}

	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()

	vars := map[string]string{"version": "9999.9999"}
	err := h(ctx, resp, req, vars)

	if !strings.Contains(err.Error(), "client version 9999.9999 is too new. Maximum supported API version is 1.10.0") {
		t.Fatalf("Expected too new client error, got %v", err)
	}
}

func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		if httputils.VersionFromContext(ctx) == "" {
			t.Fatal("Expected version, got empty string")
		}
		return nil
	}

	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()

	vars := map[string]string{"version": "0.1"}
	err := h(ctx, resp, req, vars)

	assert.Error(t, err)
	hdr := resp.Result().Header
	assert.Contains(t, hdr.Get("Server"), "Docker/"+defaultVersion)
	assert.Contains(t, hdr.Get("Server"), runtime.GOOS)
	assert.Equal(t, hdr.Get("API-Version"), defaultVersion)
	assert.Equal(t, hdr.Get("OSType"), runtime.GOOS)
}
<commit_msg>Improve API version-middleware test<commit_after>package middleware

import (
	"net/http"
	"net/http/httptest"
	"runtime"
	"testing"

	"github.com/docker/docker/api/server/httputils"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
)

func TestVersionMiddlewareVersion(t *testing.T) {
	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	expectedVersion := defaultVersion
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		v := httputils.VersionFromContext(ctx)
		assert.Equal(t, expectedVersion, v)
		return nil
	}

	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()

	tests := []struct {
		reqVersion      string
		expectedVersion string
		errString       string
	}{
		{
			expectedVersion: "1.10.0",
		},
		{
			reqVersion:      "1.9.0",
			expectedVersion: "1.9.0",
		},
		{
			reqVersion: "0.1",
			errString:  "client version 0.1 is too old. Minimum supported API version is 1.2.0, please upgrade your client to a newer version",
		},
		{
			reqVersion: "9999.9999",
			errString:  "client version 9999.9999 is too new. Maximum supported API version is 1.10.0",
		},
	}

	for _, test := range tests {
		expectedVersion = test.expectedVersion

		err := h(ctx, resp, req, map[string]string{"version": test.reqVersion})

		if test.errString != "" {
			assert.EqualError(t, err, test.errString)
		} else {
			assert.NoError(t, err)
		}
	}
}

func TestVersionMiddlewareWithErrorsReturnsHeaders(t *testing.T) {
	handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
		v := httputils.VersionFromContext(ctx)
		assert.NotEmpty(t, v)
		return nil
	}

	defaultVersion := "1.10.0"
	minVersion := "1.2.0"
	m := NewVersionMiddleware(defaultVersion, defaultVersion, minVersion)
	h := m.WrapHandler(handler)

	req, _ := http.NewRequest("GET", "/containers/json", nil)
	resp := httptest.NewRecorder()
	ctx := context.Background()

	vars := map[string]string{"version": "0.1"}
	err := h(ctx, resp, req, vars)
	assert.Error(t, err)

	hdr := resp.Result().Header
	assert.Contains(t, hdr.Get("Server"), "Docker/"+defaultVersion)
	assert.Contains(t, hdr.Get("Server"), runtime.GOOS)
	assert.Equal(t, hdr.Get("API-Version"), defaultVersion)
	assert.Equal(t, hdr.Get("OSType"), runtime.GOOS)
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package unitassigner

import (
	"sync"

	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/params"
)

var _ = gc.Suite(testsuite{})

type testsuite struct{}

func (testsuite) TestAssignUnits(c *gc.C) {
	f := &fakeAssignCaller{c: c, response: params.ErrorResults{
		Results: []params.ErrorResult{
			{},
			{},
		}}}
	api := New(f)
	ids := []names.UnitTag{names.NewUnitTag("mysql/0"), names.NewUnitTag("mysql/1")}
	errs, err := api.AssignUnits(ids)
	c.Assert(f.request, gc.Equals, "AssignUnits")
	c.Assert(f.params, gc.DeepEquals,
		params.Entities{[]params.Entity{
			{Tag: "unit-mysql-0"},
			{Tag: "unit-mysql-1"},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(errs, gc.DeepEquals, []error{nil, nil})
}

func (testsuite) TestAssignUnitsNotFound(c *gc.C) {
	f := &fakeAssignCaller{c: c, response: params.ErrorResults{
		Results: []params.ErrorResult{
			{Error: &params.Error{Code: params.CodeNotFound}},
		}}}
	api := New(f)
	ids := []names.UnitTag{names.NewUnitTag("mysql/0")}
	errs, err := api.AssignUnits(ids)
	f.Lock()
	c.Assert(f.request, gc.Equals, "AssignUnits")
	c.Assert(f.params, gc.DeepEquals,
		params.Entities{[]params.Entity{
			{Tag: "unit-mysql-0"},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(errs, gc.HasLen, 1)
	c.Assert(errs[0], jc.Satisfies, errors.IsNotFound)
}

func (testsuite) TestWatchUnitAssignment(c *gc.C) {
	f := &fakeWatchCaller{
		c:        c,
		response: params.StringsWatchResult{},
	}
	api := New(f)
	w, err := api.WatchUnitAssignments()
	f.Lock()
	c.Assert(f.request, gc.Equals, "WatchUnitAssignments")
	c.Assert(f.params, gc.IsNil)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(w, gc.NotNil)
}

type fakeAssignCaller struct {
	base.APICaller
	sync.Mutex
	request  string
	params   interface{}
	response params.ErrorResults
	err      error
	c        *gc.C
}

func (f *fakeAssignCaller) APICall(objType string, version int, id, request string, param, response interface{}) error {
	f.Lock()
	defer f.Unlock()
	f.request = request
	f.params = param
	res, ok := response.(*params.ErrorResults)
	if !ok {
		f.c.Errorf("Expected *params.ErrorResults as response, but was %#v", response)
	} else {
		*res = f.response
	}
	return f.err

}

func (*fakeAssignCaller) BestFacadeVersion(facade string) int {
	return 1
}

type fakeWatchCaller struct {
	base.APICaller
	sync.Mutex
	request  string
	params   interface{}
	response params.StringsWatchResult
	err      error
	c        *gc.C
}

func (f *fakeWatchCaller) APICall(objType string, version int, id, request string, param, response interface{}) error {
	f.Lock()
	defer f.Unlock()
	f.request = request
	f.params = param
	_, ok := response.(*params.StringsWatchResult)
	if !ok {
		f.c.Errorf("Expected *params.StringsWatchResult as response, but was %#v", response)
	}
	return f.err
}

func (*fakeWatchCaller) BestFacadeVersion(facade string) int {
	return 1
}
<commit_msg>api/unitassigner: fix intermittent test failure<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package unitassigner

import (
	"sync"

	"github.com/juju/errors"
	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"
	"gopkg.in/juju/names.v2"

	"github.com/juju/juju/api/base"
	"github.com/juju/juju/apiserver/params"
)

var _ = gc.Suite(testsuite{})

type testsuite struct{}

func (testsuite) TestAssignUnits(c *gc.C) {
	f := &fakeAssignCaller{c: c, response: params.ErrorResults{
		Results: []params.ErrorResult{
			{},
			{},
		}}}
	api := New(f)
	ids := []names.UnitTag{names.NewUnitTag("mysql/0"), names.NewUnitTag("mysql/1")}
	errs, err := api.AssignUnits(ids)
	c.Assert(f.request, gc.Equals, "AssignUnits")
	c.Assert(f.params, gc.DeepEquals,
		params.Entities{[]params.Entity{
			{Tag: "unit-mysql-0"},
			{Tag: "unit-mysql-1"},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(errs, gc.DeepEquals, []error{nil, nil})
}

func (testsuite) TestAssignUnitsNotFound(c *gc.C) {
	f := &fakeAssignCaller{c: c, response: params.ErrorResults{
		Results: []params.ErrorResult{
			{Error: &params.Error{Code: params.CodeNotFound}},
		}}}
	api := New(f)
	ids := []names.UnitTag{names.NewUnitTag("mysql/0")}
	errs, err := api.AssignUnits(ids)
	f.Lock()
	c.Assert(f.request, gc.Equals, "AssignUnits")
	c.Assert(f.params, gc.DeepEquals,
		params.Entities{[]params.Entity{
			{Tag: "unit-mysql-0"},
		}},
	)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(errs, gc.HasLen, 1)
	c.Assert(errs[0], jc.Satisfies, errors.IsNotFound)
}

func (testsuite) TestWatchUnitAssignment(c *gc.C) {
	f := &fakeWatchCaller{
		c:        c,
		response: params.StringsWatchResult{},
	}
	api := New(f)
	w, err := api.WatchUnitAssignments()
	f.Lock()
	c.Assert(f.request, gc.Equals, "WatchUnitAssignments")
	c.Assert(f.params, gc.IsNil)
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(w, gc.NotNil)
}

type fakeAssignCaller struct {
	base.APICaller
	sync.Mutex
	request  string
	params   interface{}
	response params.ErrorResults
	err      error
	c        *gc.C
}

func (f *fakeAssignCaller) APICall(objType string, version int, id, request string, param, response interface{}) error {
	f.Lock()
	defer f.Unlock()
	f.request = request
	f.params = param
	res, ok := response.(*params.ErrorResults)
	if !ok {
		f.c.Errorf("Expected *params.ErrorResults as response, but was %#v", response)
	} else {
		*res = f.response
	}
	return f.err

}

func (*fakeAssignCaller) BestFacadeVersion(facade string) int {
	return 1
}

type fakeWatchCaller struct {
	base.APICaller
	sync.Mutex
	request  string
	params   interface{}
	response params.StringsWatchResult
	err      error
	c        *gc.C
}

func (f *fakeWatchCaller) APICall(objType string, version int, id, request string, param, response interface{}) error {
	f.Lock()
	defer f.Unlock()

	// We only care for the first request as that is all the tests
	// assert on. The watcher (StringsWatcher) is continuously
	// running and this function gets called repeatedly
	// overwriting f.request leading to intermittent failures.
	// Fixes: https://bugs.launchpad.net/juju/+bug/1606302

	if f.request == "" {
		f.request = request
		f.params = param
		_, ok := response.(*params.StringsWatchResult)
		if !ok {
			f.c.Errorf("Expected *params.StringsWatchResult as response, but was %#v", response)
		}
	}
	return f.err
}

func (*fakeWatchCaller) BestFacadeVersion(facade string) int {
	return 1
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"flag"
	"fmt"
	"time"

	"k8s.io/client-go/1.4/kubernetes"
	"k8s.io/client-go/1.4/pkg/api"
	"k8s.io/client-go/1.4/tools/clientcmd"
)

var (
	kubeconfig = flag.String("kubeconfig", "./config", "absolute path to the kubeconfig file")
)

func main() {
	flag.Parse()
	// uses the current context in kubeconfig
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}
	// creates the clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}
	for {
		pods, err := clientset.Core().Pods("").List(api.ListOptions{})
		if err != nil {
			panic(err.Error())
		}
		fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
		time.Sleep(10 * time.Second)
	}
}
<commit_msg>Make out-of-cluster example buildable<commit_after>/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"flag"
	"fmt"
	"time"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/pkg/api/v1"
	"k8s.io/client-go/tools/clientcmd"
)

var (
	kubeconfig = flag.String("kubeconfig", "./config", "absolute path to the kubeconfig file")
)

func main() {
	flag.Parse()
	// uses the current context in kubeconfig
	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
	if err != nil {
		panic(err.Error())
	}
	// creates the clientset
	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err.Error())
	}
	for {
		pods, err := clientset.Core().Pods("").List(v1.ListOptions{})
		if err != nil {
			panic(err.Error())
		}
		fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
		time.Sleep(10 * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"

	"github.com/Queens-Hacks/Propagate/sim"
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

var maxSpiral string = `
function foo (n)
	  i = 0
	  while i<n do
          i= i+1
	  grow(getdir(n))
	  end

      if n > 0 then return foo(n - 1) end
end

function getdir(n)
   v = n % 4
   if v == 0 then return "up" end
   if v == 1 then return "right" end
   if v == 2 then return "down" end
   if v == 3 then return "left" end

end

grow("up")
grow("up")
grow("up")

foo(8);
`
var maxMeander string = `
while 1 do

	while math.random(10)<8 do
		grow("up")
	end
	while math.random(10)<8 do
		grow("left")
	end
	while math.random(10)<8 do
		grow("up")
	end
	while math.random(10)<8 do
		grow("right")
	end

end

`
var jakeRand string = `
dir = "up"
while 1 do
	d = math.random(6)
	if d == 0 then dir = "right" end
	if d == 1 then dir = "up" end
	if d == 2 then dir = "left" end
	grow(dir)
	grow(dir)
	grow(dir)
end

`

var maxMemory string = `
while 1 do
	grow("up")
	grow("up")
	split("up","up")
	grow("left")
	grow("left")
	split("left","left")
	grow("right")
	grow("right")
	split("right","right")
end
`

var crystal string = `
while 1 do

  grow("up")
  grow("up")
  grow("up")
  grow("up")

  split("up", "right")

  split("left", "left")
  split("right", "right")
end
`
var coral string = `

while 1 do
n=0
 while math.random(10)>n do
  grow("left")
  grow("up")
  n= n+1
end
n = 0
while math.random(10)>n do
  grow("right")
  grow("up")
n= n+1
end
end

`

var twistyLeft string = `
while 1 do
  grow("left")
  grow("up")
  grow("up")
end
`

var twistyUp string = `
while 1 do
  grow("left")
  grow("up")
  grow("up")
  grow("left")
  grow("up")
  grow("up")
  grow("right")
  grow("up")
  grow("up")
  grow("right")
  grow("up")
  grow("up")
end
`

var upUp string = `
while 1 do
  grow("up")
end
`

var fearnLeft string = `
while 1 do
  if meta() == "" then
    grow("up")
    grow("up")
	split("left", "left")
  else
  	grow("left")
  end
end

`

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	total := make(chan []byte)
	diff := make(chan []byte)
	actions := make(chan sim.Action)

	s := sim.NewState(500, 125)

	species := s.AddSpecies(256, maxMeander, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(244, jakeRand, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(128, upUp, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(63, crystal, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(44, maxMemory, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(14, fearnLeft, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(1, coral, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(275, twistyUp, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(300, twistyLeft, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	port := ":4444"

	logrus.Infof("Listening on port %s", port)
	go New(ctx, total, diff, actions, port)

	ss := s.StartSimulate(actions)
	for {
		ms := <-ss
		total <- ms.State
		diff <- ms.Diff
	}
}
<commit_msg>branching ai<commit_after>package main

import (
	"math/rand"

	"github.com/Queens-Hacks/Propagate/sim"
	"github.com/Sirupsen/logrus"
	"golang.org/x/net/context"
)

var maxSpiral string = `
function foo (n)
	  i = 0
	  while i<n do
          i= i+1
	  grow(getdir(n))
	  end

      if n > 0 then return foo(n - 1) end
end

function getdir(n)
   v = n % 4
   if v == 0 then return "up" end
   if v == 1 then return "right" end
   if v == 2 then return "down" end
   if v == 3 then return "left" end

end

grow("up")
grow("up")
grow("up")

foo(8);
`
var maxMeander string = `
while 1 do

	while math.random(10)<8 do
		grow("up")
	end
	while math.random(10)<8 do
		grow("left")
	end
	while math.random(10)<8 do
		grow("up")
	end
	while math.random(10)<8 do
		grow("right")
	end

end

`
var jakeRand string = `
local i = 10
while i > 0 do
  grow("up")
  grow("up")
  if math.random(2) == 1 then
     grow("left")
     grow("left")
     split("left", "left")
  else
     grow("right")
     grow("right")
     split("right", "right")
  end
end
`

var maxMemory string = `
while 1 do
	grow("up")
	grow("up")
	split("up","up")
	grow("left")
	grow("left")
	split("left","left")
	grow("right")
	grow("right")
	split("right","right")
end
`

var crystal string = `
while 1 do

  grow("up")
  grow("up")
  grow("up")
  grow("up")

  split("up", "right")

  split("left", "left")
  split("right", "right")
end
`
var coral string = `

while 1 do
n=0
 while math.random(10)>n do
  grow("left")
  grow("up")
  n= n+1
end
n = 0
while math.random(10)>n do
  grow("right")
  grow("up")
n= n+1
end
end

`

var twistyLeft string = `
while 1 do
  grow("left")
  grow("up")
  grow("up")
end
`

var twistyUp string = `
while 1 do
  grow("left")
  grow("up")
  grow("up")
  grow("left")
  grow("up")
  grow("up")
  grow("right")
  grow("up")
  grow("up")
  grow("right")
  grow("up")
  grow("up")
end
`

var upUp string = `
while 1 do
  grow("up")
end
`

var fearnLeft string = `
while 1 do
  if meta() == "" then
    grow("up")
    grow("up")
	split("left", "left")
  else
  	grow("left")
  end
end

`

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	total := make(chan []byte)
	diff := make(chan []byte)
	actions := make(chan sim.Action)

	s := sim.NewState(500, 125)

	species := s.AddSpecies(256, maxMeander, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(244, jakeRand, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(128, upUp, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(63, crystal, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(44, maxMemory, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(14, fearnLeft, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(1, coral, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(275, twistyUp, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	species = s.AddSpecies(300, twistyLeft, "Me")
	for i := 0; i < 10; i++ {
		s.AddSpore(sim.Location{rand.Intn(500), 75}, species)
	}

	port := ":4444"

	logrus.Infof("Listening on port %s", port)
	go New(ctx, total, diff, actions, port)

	ss := s.StartSimulate(actions)
	for {
		ms := <-ss
		total <- ms.State
		diff <- ms.Diff
	}
}
<|endoftext|>


<commit_before>package couchbase

/*

The goal here is to map a hostname:port combination to another hostname:port
combination. The original hostname:port gives the name and regular KV port
of a couchbase server. We want to determine the corresponding SSL KV port.

To do this, we have a pool services structure, as obtained from
the /pools/default/nodeServices API.

For a fully configured two-node system, the structure may look like this:
{"rev":32,"nodesExt":[
	{"services":{"mgmt":8091,"mgmtSSL":18091,"fts":8094,"ftsSSL":18094,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211},"hostname":"172.23.123.101"},
	{"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211,"n1ql":8093,"n1qlSSL":18093},"thisNode":true,"hostname":"172.23.123.102"}]}

In this case, note the "hostname" fields, and the "kv" and "kvSSL" fields.

For a single-node system, perhaps brought up for testing, the structure may look like this:
{"rev":66,"nodesExt":[
	{"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"kv":11210,"kvSSL":11207,"capi":8092,"capiSSL":18092,"projector":9999,"n1ql":8093,"n1qlSSL":18093},"thisNode":true}],"clusterCapabilitiesVer":[1,0],"clusterCapabilities":{"n1ql":["enhancedPreparedStatements"]}}

Here, note that there is only a single entry in the "nodeExt" array and that it does not have a "hostname" field.
We will assume that either hostname fields are present, or there is only a single node.
*/

import (
	"encoding/json"
	"fmt"
	"net"
	"strconv"
)

func ParsePoolServices(jsonInput string) (*PoolServices, error) {
	ps := &PoolServices{}
	err := json.Unmarshal([]byte(jsonInput), ps)
	return ps, err
}

// Accepts a "host:port" string representing the KV TCP port and the pools
// nodeServices payload and returns a host:port string representing the KV
// TLS port on the same node as the KV TCP port.
func MapKVtoSSL(hostport string, ps *PoolServices) (string, bool, error) {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return "", false, fmt.Errorf("Unable to split hostport %s: %v", hostport, err)
	}

	portInt, err := strconv.Atoi(port)
	if err != nil {
		return "", false, fmt.Errorf("Unable to parse host/port combination %s: %v", hostport, err)
	}

	var ns *NodeServices
	for i := range ps.NodesExt {
		hostname := ps.NodesExt[i].Hostname
		if len(hostname) != 0 && hostname != host {
			/* If the hostname is the empty string, it means the node (and by extension
			   the cluster) is configured on the loopback. Further, it means that the client
			   should use whatever hostname it used to get the nodeServices information in
			   the first place to access the cluster. Thus, when the hostname is empty in
			   the nodeService entry we can assume that client will use the hostname it used
			   to access the KV TCP endpoint - and thus that it automatically "matches".
			   If hostname is not empty and doesn't match then we move to the next entry.
			*/
			continue
		}
		kvPort, found := ps.NodesExt[i].Services["kv"]
		if !found {
			/* not a node with a KV service  */
			continue
		}
		if kvPort == portInt {
			ns = &(ps.NodesExt[i])
			break
		}
	}

	if ns == nil {
		return "", false, fmt.Errorf("Unable to parse host/port combination %s: no matching node found among %d", hostport, len(ps.NodesExt))
	}
	kvSSL, found := ns.Services["kvSSL"]
	if !found {
		return "", false, fmt.Errorf("Unable to map host/port combination %s: target host has no kvSSL port listed", hostport)
	}

	//Don't encrypt for communication between local nodes
	if len(ns.Hostname) == 0 || ns.ThisNode {
		return hostport, false, nil
	}

	if net.ParseIP(host).To4() == nil { // IPv6
		// Prefix and suffix square brackets as SplitHostPort removes them,
		// see: https://golang.org/pkg/net/#SplitHostPort
		host = "[" + host + "]"
	}

	return fmt.Sprintf("%s:%d", host, kvSSL), true, nil
}
<commit_msg>MB-36939: Prefix-suffix square brackets only in case of IPv6 address<commit_after>package couchbase

/*

The goal here is to map a hostname:port combination to another hostname:port
combination. The original hostname:port gives the name and regular KV port
of a couchbase server. We want to determine the corresponding SSL KV port.

To do this, we have a pool services structure, as obtained from
the /pools/default/nodeServices API.

For a fully configured two-node system, the structure may look like this:
{"rev":32,"nodesExt":[
	{"services":{"mgmt":8091,"mgmtSSL":18091,"fts":8094,"ftsSSL":18094,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211},"hostname":"172.23.123.101"},
	{"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"capiSSL":18092,"capi":8092,"kvSSL":11207,"projector":9999,"kv":11210,"moxi":11211,"n1ql":8093,"n1qlSSL":18093},"thisNode":true,"hostname":"172.23.123.102"}]}

In this case, note the "hostname" fields, and the "kv" and "kvSSL" fields.

For a single-node system, perhaps brought up for testing, the structure may look like this:
{"rev":66,"nodesExt":[
	{"services":{"mgmt":8091,"mgmtSSL":18091,"indexAdmin":9100,"indexScan":9101,"indexHttp":9102,"indexStreamInit":9103,"indexStreamCatchup":9104,"indexStreamMaint":9105,"indexHttps":19102,"kv":11210,"kvSSL":11207,"capi":8092,"capiSSL":18092,"projector":9999,"n1ql":8093,"n1qlSSL":18093},"thisNode":true}],"clusterCapabilitiesVer":[1,0],"clusterCapabilities":{"n1ql":["enhancedPreparedStatements"]}}

Here, note that there is only a single entry in the "nodeExt" array and that it does not have a "hostname" field.
We will assume that either hostname fields are present, or there is only a single node.
*/

import (
	"encoding/json"
	"fmt"
	"net"
	"strconv"
)

func ParsePoolServices(jsonInput string) (*PoolServices, error) {
	ps := &PoolServices{}
	err := json.Unmarshal([]byte(jsonInput), ps)
	return ps, err
}

// Accepts a "host:port" string representing the KV TCP port and the pools
// nodeServices payload and returns a host:port string representing the KV
// TLS port on the same node as the KV TCP port.
func MapKVtoSSL(hostport string, ps *PoolServices) (string, bool, error) {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return "", false, fmt.Errorf("Unable to split hostport %s: %v", hostport, err)
	}

	portInt, err := strconv.Atoi(port)
	if err != nil {
		return "", false, fmt.Errorf("Unable to parse host/port combination %s: %v", hostport, err)
	}

	var ns *NodeServices
	for i := range ps.NodesExt {
		hostname := ps.NodesExt[i].Hostname
		if len(hostname) != 0 && hostname != host {
			/* If the hostname is the empty string, it means the node (and by extension
			   the cluster) is configured on the loopback. Further, it means that the client
			   should use whatever hostname it used to get the nodeServices information in
			   the first place to access the cluster. Thus, when the hostname is empty in
			   the nodeService entry we can assume that client will use the hostname it used
			   to access the KV TCP endpoint - and thus that it automatically "matches".
			   If hostname is not empty and doesn't match then we move to the next entry.
			*/
			continue
		}
		kvPort, found := ps.NodesExt[i].Services["kv"]
		if !found {
			/* not a node with a KV service  */
			continue
		}
		if kvPort == portInt {
			ns = &(ps.NodesExt[i])
			break
		}
	}

	if ns == nil {
		return "", false, fmt.Errorf("Unable to parse host/port combination %s: no matching node found among %d", hostport, len(ps.NodesExt))
	}
	kvSSL, found := ns.Services["kvSSL"]
	if !found {
		return "", false, fmt.Errorf("Unable to map host/port combination %s: target host has no kvSSL port listed", hostport)
	}

	//Don't encrypt for communication between local nodes
	if len(ns.Hostname) == 0 || ns.ThisNode {
		return hostport, false, nil
	}

	ip := net.ParseIP(host)
	if ip != nil && ip.To4() == nil && ip.To16() != nil { // IPv6 and not a FQDN
		// Prefix and suffix square brackets as SplitHostPort removes them,
		// see: https://golang.org/pkg/net/#SplitHostPort
		host = "[" + host + "]"
	}

	return fmt.Sprintf("%s:%d", host, kvSSL), true, nil
}
<|endoftext|>


<commit_before>/*
Package portping provides simple functions to ping TCP ports.
It also includes a simple command line interface.
 */
package portping

import (
	"net"
	"time"
)

// Ping connects to the specified host and port
// using net.DialTimeout and network "tcp".
func Ping(host, port string) error {
	addr := net.JoinHostPort(host, port)
	conn, err := net.DialTimeout("tcp", addr, 10*time.Second)
	if conn != nil {
		defer conn.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

// PingN calls Ping the specified number of times,
// and sends the results to the given channel.
func PingN(host, port string, count int, c chan error) {
	for i := 0; i < count; i++ {
		c <- Ping(host, port)
	}
}

// FormatResult converts the result returned by Ping to string.
func FormatResult(err error) string {
	if err == nil {
		return "success"
	}
	switch err := err.(type) {
	case *net.OpError:
		return err.Err.Error()
	default:
		return err.Error()
	}
}
<commit_msg>made default timeout a constant<commit_after>/*
Package portping provides simple functions to ping TCP ports.
It also includes a simple command line interface.
 */
package portping

import (
	"net"
	"time"
)

const defaultTimeout = 10 * time.Second

// Ping connects to the specified host and port
// using net.DialTimeout and network "tcp".
func Ping(host, port string) error {
	addr := net.JoinHostPort(host, port)
	conn, err := net.DialTimeout("tcp", addr, defaultTimeout)
	if conn != nil {
		defer conn.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

// PingN calls Ping the specified number of times,
// and sends the results to the given channel.
func PingN(host, port string, count int, c chan error) {
	for i := 0; i < count; i++ {
		c <- Ping(host, port)
	}
}

// FormatResult converts the result returned by Ping to string.
func FormatResult(err error) string {
	if err == nil {
		return "success"
	}
	switch err := err.(type) {
	case *net.OpError:
		return err.Err.Error()
	default:
		return err.Error()
	}
}
<|endoftext|>


<commit_before>/*
Package portping provides simple functions to ping TCP ports.
It also includes a simple command line interface.
 */
package portping

import (
	"net"
	"time"
)

// Ping connects to the address on the named network,
// using net.DialTimeout. If a successful connection is made,
// return nil. Otherwise return the error.
func Ping(network, address string, timeout time.Duration) error {
	conn, err := net.DialTimeout(network, address, timeout)
	if conn != nil {
		defer conn.Close()
	}
	if err != nil {
		return err
	}
	return nil
}

// PingN calls Ping the specified number of times,
// and sends the results to the given channel.
func PingN(network, address string, timeout time.Duration, count int, c chan <- error) {
	for i := 0; i < count; i++ {
		c <- Ping(network, address, timeout)
	}
}
<commit_msg>simply return err, skip the if<commit_after>/*
Package portping provides simple functions to ping TCP ports.
It also includes a simple command line interface.
 */
package portping

import (
	"net"
	"time"
)

// Ping connects to the address on the named network,
// using net.DialTimeout. If a successful connection is made,
// return nil. Otherwise return the error.
func Ping(network, address string, timeout time.Duration) error {
	conn, err := net.DialTimeout(network, address, timeout)
	if conn != nil {
		defer conn.Close()
	}
	return err
}

// PingN calls Ping the specified number of times,
// and sends the results to the given channel.
func PingN(network, address string, timeout time.Duration, count int, c chan <- error) {
	for i := 0; i < count; i++ {
		c <- Ping(network, address, timeout)
	}
}
<|endoftext|>