<commit_before>package main

import (
	"fmt"
	"github.com/alexjohnj/flasher/tbutils"
	"github.com/codegangsta/cli"
	"github.com/nsf/termbox-go"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "flasher"
	app.Version = "0.3.0"
	app.Author = "Alex Jackson"
	app.Email = "alex@alexj.org"

	app.Commands = []cli.Command{
		{
			Name:      "flash",
			ShortName: "f",
			Usage:     "flasher flash [flashcard-file.json]",
			Action:    cliFlash,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "no-shuffle, n",
					Usage: "Presents flashcards in the order they are written in the source JSON file.",
				},
			},
		},
		{
			Name:      "info",
			ShortName: "i",
			Usage:     "flasher info [flashcard-file.json]",
			Action:    cliInfo,
		},
	}
	app.Run(os.Args)
}

func cliFlash(c *cli.Context) {
	// Load flashcards

	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "flash")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatal(err)
	}

	if !c.Bool("no-shuffle") {
		flashcardStack.shuffle()
	}

	// Init termbox
	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()
	drawAll(flashcardStack)

	//Main Run loop
mainloop:
	for {
		switch event := termbox.PollEvent(); event.Type {
		case termbox.EventKey:
			switch event.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyEnter, termbox.KeyArrowRight:
				flashcardStack.advanceStack()
			case termbox.KeyBackspace2, termbox.KeyArrowLeft:
				flashcardStack.revertStack()
			}

			switch event.Ch {
			case 'q':
				break mainloop

			case 'l':
				flashcardStack.advanceStack()

			case 'h':
				flashcardStack.revertStack()

			case 'r':
				if flashcardStack.atEndOfStack() {
					flashcardStack.StackIndex = 0
					flashcardStack.ShowAnswer = false
				}

			case 'x':
				if flashcardStack.atEndOfStack() {
					flashcardStack.shuffle()
					flashcardStack.StackIndex = 0
					flashcardStack.ShowAnswer = false
				}
			}

		case termbox.EventResize:
			drawAll(flashcardStack)
		}

		drawAll(flashcardStack)
	}
}

func cliInfo(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "info")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatalf("%s is an invalid file: %s", c.Args()[0], err.Error())
	}

	fmt.Printf("Deck Name: %s\nAuthor: %s\nNumber of Cards: %d\n", flashcardStack.Title, flashcardStack.Author, len(flashcardStack.Flashcards))
}

// TODO: Break up mega function
func drawAll(stack *cardStack) {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	w, h := termbox.Size()

	// Draw termbox border
	for x := 0; x <= w; x++ {
		termbox.SetCell(0+x, 0, ' ', termbox.ColorBlack, termbox.ColorWhite)
		termbox.SetCell(0+x, h, ' ', termbox.ColorBlack, termbox.ColorWhite)
	}

	// Draw the app name & version
	appString := fmt.Sprintf("%s - %s", "flasher", "0.3.0") // TODO: Modify drawAll() to accept *cli.Context so this isn't hard coded
	for index, ch := range appString {
		termbox.SetCell(2+index, 0, ch, termbox.ColorBlack, termbox.ColorWhite)
	}

	// Draw the Stack's title
	titleXCoord := tbutils.CalculateXCenterCoord(stack.Title)
	for index, ch := range stack.Title {
		termbox.SetCell(titleXCoord+index, 0, ch, termbox.ColorBlack, termbox.ColorWhite)
	}

	// Draw the current card
	currentQuestion := stack.getCurrentFlashcard()
	currentQuestion.drawQuestion()
	if stack.ShowAnswer {
		currentQuestion.drawAnswer()
		// Draw the Q/A divider
		for x := 0; x < w; x++ {
			termbox.SetCell(x, (3 * h / 8), '-', termbox.ColorBlue, termbox.ColorDefault)
		}
	}

	// Draw end of stack message
	if stack.atEndOfStack() {
		endOfStackMessageLine1 := "End of Stack..."
		endOfStackMessageLine2 := "(q)Quit (r)Restart (x)Reshuffle & Restart."
		eosXCoord1, eosYCoord1 := tbutils.CalculateXCenterCoord(endOfStackMessageLine1), (3 * (h / 4))
		eosXCoord2, eosYCoord2 := tbutils.CalculateXCenterCoord(endOfStackMessageLine2), (3*h/4)+1
		tbutils.DrawText(eosXCoord1, eosYCoord1, endOfStackMessageLine1)
		tbutils.DrawText(eosXCoord2, eosYCoord2, endOfStackMessageLine2)
	}

	// Draw the current index
	indexStr := fmt.Sprintf("(%d/%d)", stack.StackIndex+1, len(stack.Flashcards))
	indexXCoord, indexYCoord := tbutils.CalculateXCenterCoord(indexStr), h-1
	tbutils.DrawText(indexXCoord, indexYCoord, indexStr)

	// Write out the back buffer
	termbox.Flush()
}
<commit_msg>Updated new UI design to use tbutils<commit_after>package main

import (
	"fmt"
	"github.com/alexjohnj/flasher/tbutils"
	"github.com/codegangsta/cli"
	"github.com/nsf/termbox-go"
	"log"
	"os"
)

func main() {
	app := cli.NewApp()
	app.Name = "flasher"
	app.Version = "0.3.0"
	app.Author = "Alex Jackson"
	app.Email = "alex@alexj.org"

	app.Commands = []cli.Command{
		{
			Name:      "flash",
			ShortName: "f",
			Usage:     "flasher flash [flashcard-file.json]",
			Action:    cliFlash,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "no-shuffle, n",
					Usage: "Presents flashcards in the order they are written in the source JSON file.",
				},
			},
		},
		{
			Name:      "info",
			ShortName: "i",
			Usage:     "flasher info [flashcard-file.json]",
			Action:    cliInfo,
		},
	}
	app.Run(os.Args)
}

func cliFlash(c *cli.Context) {
	// Load flashcards

	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "flash")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatal(err)
	}

	if !c.Bool("no-shuffle") {
		flashcardStack.shuffle()
	}

	// Init termbox
	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()
	drawAll(flashcardStack)

	//Main Run loop
mainloop:
	for {
		switch event := termbox.PollEvent(); event.Type {
		case termbox.EventKey:
			switch event.Key {
			case termbox.KeyEsc, termbox.KeyCtrlC:
				break mainloop
			case termbox.KeyEnter, termbox.KeyArrowRight:
				flashcardStack.advanceStack()
			case termbox.KeyBackspace2, termbox.KeyArrowLeft:
				flashcardStack.revertStack()
			}

			switch event.Ch {
			case 'q':
				break mainloop

			case 'l':
				flashcardStack.advanceStack()

			case 'h':
				flashcardStack.revertStack()

			case 'r':
				if flashcardStack.atEndOfStack() {
					flashcardStack.StackIndex = 0
					flashcardStack.ShowAnswer = false
				}

			case 'x':
				if flashcardStack.atEndOfStack() {
					flashcardStack.shuffle()
					flashcardStack.StackIndex = 0
					flashcardStack.ShowAnswer = false
				}
			}

		case termbox.EventResize:
			drawAll(flashcardStack)
		}

		drawAll(flashcardStack)
	}
}

func cliInfo(c *cli.Context) {
	if len(c.Args()) != 1 {
		log.Printf("Incorrect usage\n")
		cli.ShowCommandHelp(c, "info")
		os.Exit(1)
	}

	flashcardStack := new(cardStack)
	err := flashcardStack.loadFlashcardStack(c.Args()[0])

	if err != nil {
		log.Fatalf("%s is an invalid file: %s", c.Args()[0], err.Error())
	}

	fmt.Printf("Deck Name: %s\nAuthor: %s\nNumber of Cards: %d\n", flashcardStack.Title, flashcardStack.Author, len(flashcardStack.Flashcards))
}

// TODO: Break up mega function
func drawAll(stack *cardStack) {
	termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
	w, h := termbox.Size()

	// Draw termbox border
	for x := 0; x <= w; x++ {
		termbox.SetCell(0+x, 0, ' ', termbox.ColorBlack, termbox.ColorWhite)
		termbox.SetCell(0+x, h, ' ', termbox.ColorBlack, termbox.ColorWhite)
	}

	// Draw the app name & version
	appString := fmt.Sprintf("%s - %s", "flasher", "0.3.0") // TODO: Modify drawAll() to accept *cli.Context so this isn't hard coded
	tbutils.DrawRichText(2, 0, appString, termbox.ColorBlack, termbox.ColorWhite)

	// Draw the Stack's title
	titleXCoord := tbutils.CalculateXCenterCoord(stack.Title)
	tbutils.DrawRichText(titleXCoord, 0, stack.Title, termbox.ColorBlack, termbox.ColorWhite)

	// Draw the current card
	currentQuestion := stack.getCurrentFlashcard()
	currentQuestion.drawQuestion()
	if stack.ShowAnswer {
		currentQuestion.drawAnswer()
		// Draw the Q/A divider
		for x := 0; x < w; x++ {
			termbox.SetCell(x, (3 * h / 8), '-', termbox.ColorBlue, termbox.ColorDefault)
		}
	}

	// Draw end of stack message
	if stack.atEndOfStack() {
		endOfStackMessageLine1 := "End of Stack..."
		endOfStackMessageLine2 := "(q)Quit (r)Restart (x)Reshuffle & Restart."
		eosXCoord1, eosYCoord1 := tbutils.CalculateXCenterCoord(endOfStackMessageLine1), (3 * (h / 4))
		eosXCoord2, eosYCoord2 := tbutils.CalculateXCenterCoord(endOfStackMessageLine2), (3*h/4)+1
		tbutils.DrawText(eosXCoord1, eosYCoord1, endOfStackMessageLine1)
		tbutils.DrawText(eosXCoord2, eosYCoord2, endOfStackMessageLine2)
	}

	// Draw the current index
	indexStr := fmt.Sprintf("(%d/%d)", stack.StackIndex+1, len(stack.Flashcards))
	indexXCoord, indexYCoord := tbutils.CalculateXCenterCoord(indexStr), h-1
	tbutils.DrawText(indexXCoord, indexYCoord, indexStr)

	// Write out the back buffer
	termbox.Flush()
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"strings"
	"time"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/client"
)

type config struct {
	Server   string
	Username string
	Password string
	Timeout  int
	Check    string
	Auth     string
}

var defaultConfig = &config{}

func getCheck() string {
	return defaultConfig.Check
}

func getVoucherClient() (voucher.Interface, error) {
	switch strings.ToLower(defaultConfig.Auth) {
	case "idtoken":
		newClient, err := client.NewAuthClient(defaultConfig.Server)
		return newClient, err
	case "basic":
		newClient, err := client.NewClient(defaultConfig.Server)
		if err == nil {
			newClient.SetBasicAuth(defaultConfig.Username, defaultConfig.Password)
		}
		return newClient, err
	default:
		return nil, fmt.Errorf("invalid auth value: %q", defaultConfig.Auth)
	}
}

func newContext() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), time.Duration(defaultConfig.Timeout)*time.Second)
}
<commit_msg>cmd/voucher_client: versioned User-Agent<commit_after>package main

import (
	"context"
	"fmt"
	"strings"
	"time"

	voucher "github.com/grafeas/voucher/v2"
	"github.com/grafeas/voucher/v2/client"
)

type config struct {
	Server   string
	Username string
	Password string
	Timeout  int
	Check    string
	Auth     string
}

var defaultConfig = &config{}

func getCheck() string {
	return defaultConfig.Check
}

func getVoucherClient() (voucher.Interface, error) {
	var newClient *client.Client
	switch strings.ToLower(defaultConfig.Auth) {
	case "idtoken":
		var err error
		newClient, err = client.NewAuthClient(defaultConfig.Server)
		if err != nil {
			return nil, err
		}
	case "basic":
		var err error
		newClient, err = client.NewClient(defaultConfig.Server)
		if err != nil {
			return nil, err
		}
		newClient.SetBasicAuth(defaultConfig.Username, defaultConfig.Password)
	default:
		return nil, fmt.Errorf("invalid auth value: %q", defaultConfig.Auth)
	}

	newClient.SetUserAgent(fmt.Sprintf("voucher-client/%s", version))
	return newClient, nil
}

func newContext() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), time.Duration(defaultConfig.Timeout)*time.Second)
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd 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 fs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

var bufferPool = &sync.Pool{
	New: func() interface{} {
		buffer := make([]byte, 32*1024)
		return &buffer
	},
}

// XAttrErrorHandlers transform a non-nil xattr error.
// Return nil to ignore an error.
// xattrKey can be empty for listxattr operation.
type XAttrErrorHandler func(dst, src, xattrKey string, err error) error

type copyDirOpts struct {
	xeh XAttrErrorHandler
	// xex contains a set of xattrs to exclude when copying
	xex map[string]struct{}
}

type CopyDirOpt func(*copyDirOpts) error

// WithXAttrErrorHandler allows specifying XAttrErrorHandler
// If nil XAttrErrorHandler is specified (default), CopyDir stops
// on a non-nil xattr error.
func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt {
	return func(o *copyDirOpts) error {
		o.xeh = xeh
		return nil
	}
}

// WithAllowXAttrErrors allows ignoring xattr errors.
func WithAllowXAttrErrors() CopyDirOpt {
	xeh := func(dst, src, xattrKey string, err error) error {
		return nil
	}
	return WithXAttrErrorHandler(xeh)
}

// WithXAttrExclude allows for exclusion of specified xattr during CopyDir operation.
func WithXAttrExclude(keys ...string) CopyDirOpt {
	return func(o *copyDirOpts) error {
		if o.xex == nil {
			o.xex = make(map[string]struct{}, len(keys))
		}
		for _, key := range keys {
			o.xex[key] = struct{}{}
		}
		return nil
	}
}

// CopyDir copies the directory from src to dst.
// Most efficient copy of files is attempted.
func CopyDir(dst, src string, opts ...CopyDirOpt) error {
	var o copyDirOpts
	for _, opt := range opts {
		if err := opt(&o); err != nil {
			return err
		}
	}
	inodes := map[uint64]string{}
	return copyDirectory(dst, src, inodes, &o)
}

func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error {
	stat, err := os.Stat(src)
	if err != nil {
		return fmt.Errorf("failed to stat %s: %w", src, err)
	}
	if !stat.IsDir() {
		return fmt.Errorf("source %s is not directory", src)
	}

	if st, err := os.Stat(dst); err != nil {
		if err := os.Mkdir(dst, stat.Mode()); err != nil {
			return fmt.Errorf("failed to mkdir %s: %w", dst, err)
		}
	} else if !st.IsDir() {
		return fmt.Errorf("cannot copy to non-directory: %s", dst)
	} else {
		if err := os.Chmod(dst, stat.Mode()); err != nil {
			return fmt.Errorf("failed to chmod on %s: %w", dst, err)
		}
	}

	fis, err := ioutil.ReadDir(src)
	if err != nil {
		return fmt.Errorf("failed to read %s: %w", src, err)
	}

	if err := copyFileInfo(stat, src, dst); err != nil {
		return fmt.Errorf("failed to copy file info for %s: %w", dst, err)
	}

	if err := copyXAttrs(dst, src, o.xex, o.xeh); err != nil {
		return fmt.Errorf("failed to copy xattrs: %w", err)
	}

	for _, fi := range fis {
		source := filepath.Join(src, fi.Name())
		target := filepath.Join(dst, fi.Name())

		switch {
		case fi.IsDir():
			if err := copyDirectory(target, source, inodes, o); err != nil {
				return err
			}
			continue
		case (fi.Mode() & os.ModeType) == 0:
			link, err := getLinkSource(target, fi, inodes)
			if err != nil {
				return fmt.Errorf("failed to get hardlink: %w", err)
			}
			if link != "" {
				if err := os.Link(link, target); err != nil {
					return fmt.Errorf("failed to create hard link: %w", err)
				}
			} else if err := CopyFile(target, source); err != nil {
				return fmt.Errorf("failed to copy files: %w", err)
			}
		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
			link, err := os.Readlink(source)
			if err != nil {
				return fmt.Errorf("failed to read link: %s: %w", source, err)
			}
			if err := os.Symlink(link, target); err != nil {
				return fmt.Errorf("failed to create symlink: %s: %w", target, err)
			}
		case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
			if err := copyDevice(target, fi); err != nil {
				return fmt.Errorf("failed to create device: %w", err)
			}
		default:
			// TODO: Support pipes and sockets
			return fmt.Errorf("unsupported mode %s: %w", fi.Mode(), err)
		}

		if err := copyFileInfo(fi, source, target); err != nil {
			return fmt.Errorf("failed to copy file info: %w", err)
		}

		if err := copyXAttrs(target, source, o.xex, o.xeh); err != nil {
			return fmt.Errorf("failed to copy xattrs: %w", err)
		}
	}

	return nil
}

// CopyFile copies the source file to the target.
// The most efficient means of copying is used for the platform.
func CopyFile(target, source string) error {
	src, err := os.Open(source)
	if err != nil {
		return fmt.Errorf("failed to open source %s: %w", source, err)
	}
	defer src.Close()
	tgt, err := os.Create(target)
	if err != nil {
		return fmt.Errorf("failed to open target %s: %w", target, err)
	}
	defer tgt.Close()

	return copyFileContent(tgt, src)
}
<commit_msg>fs: fix wrapping nil err<commit_after>/*
   Copyright The containerd 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 fs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"sync"
)

var bufferPool = &sync.Pool{
	New: func() interface{} {
		buffer := make([]byte, 32*1024)
		return &buffer
	},
}

// XAttrErrorHandlers transform a non-nil xattr error.
// Return nil to ignore an error.
// xattrKey can be empty for listxattr operation.
type XAttrErrorHandler func(dst, src, xattrKey string, err error) error

type copyDirOpts struct {
	xeh XAttrErrorHandler
	// xex contains a set of xattrs to exclude when copying
	xex map[string]struct{}
}

type CopyDirOpt func(*copyDirOpts) error

// WithXAttrErrorHandler allows specifying XAttrErrorHandler
// If nil XAttrErrorHandler is specified (default), CopyDir stops
// on a non-nil xattr error.
func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt {
	return func(o *copyDirOpts) error {
		o.xeh = xeh
		return nil
	}
}

// WithAllowXAttrErrors allows ignoring xattr errors.
func WithAllowXAttrErrors() CopyDirOpt {
	xeh := func(dst, src, xattrKey string, err error) error {
		return nil
	}
	return WithXAttrErrorHandler(xeh)
}

// WithXAttrExclude allows for exclusion of specified xattr during CopyDir operation.
func WithXAttrExclude(keys ...string) CopyDirOpt {
	return func(o *copyDirOpts) error {
		if o.xex == nil {
			o.xex = make(map[string]struct{}, len(keys))
		}
		for _, key := range keys {
			o.xex[key] = struct{}{}
		}
		return nil
	}
}

// CopyDir copies the directory from src to dst.
// Most efficient copy of files is attempted.
func CopyDir(dst, src string, opts ...CopyDirOpt) error {
	var o copyDirOpts
	for _, opt := range opts {
		if err := opt(&o); err != nil {
			return err
		}
	}
	inodes := map[uint64]string{}
	return copyDirectory(dst, src, inodes, &o)
}

func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error {
	stat, err := os.Stat(src)
	if err != nil {
		return fmt.Errorf("failed to stat %s: %w", src, err)
	}
	if !stat.IsDir() {
		return fmt.Errorf("source %s is not directory", src)
	}

	if st, err := os.Stat(dst); err != nil {
		if err := os.Mkdir(dst, stat.Mode()); err != nil {
			return fmt.Errorf("failed to mkdir %s: %w", dst, err)
		}
	} else if !st.IsDir() {
		return fmt.Errorf("cannot copy to non-directory: %s", dst)
	} else {
		if err := os.Chmod(dst, stat.Mode()); err != nil {
			return fmt.Errorf("failed to chmod on %s: %w", dst, err)
		}
	}

	fis, err := ioutil.ReadDir(src)
	if err != nil {
		return fmt.Errorf("failed to read %s: %w", src, err)
	}

	if err := copyFileInfo(stat, src, dst); err != nil {
		return fmt.Errorf("failed to copy file info for %s: %w", dst, err)
	}

	if err := copyXAttrs(dst, src, o.xex, o.xeh); err != nil {
		return fmt.Errorf("failed to copy xattrs: %w", err)
	}

	for _, fi := range fis {
		source := filepath.Join(src, fi.Name())
		target := filepath.Join(dst, fi.Name())

		switch {
		case fi.IsDir():
			if err := copyDirectory(target, source, inodes, o); err != nil {
				return err
			}
			continue
		case (fi.Mode() & os.ModeType) == 0:
			link, err := getLinkSource(target, fi, inodes)
			if err != nil {
				return fmt.Errorf("failed to get hardlink: %w", err)
			}
			if link != "" {
				if err := os.Link(link, target); err != nil {
					return fmt.Errorf("failed to create hard link: %w", err)
				}
			} else if err := CopyFile(target, source); err != nil {
				return fmt.Errorf("failed to copy files: %w", err)
			}
		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
			link, err := os.Readlink(source)
			if err != nil {
				return fmt.Errorf("failed to read link: %s: %w", source, err)
			}
			if err := os.Symlink(link, target); err != nil {
				return fmt.Errorf("failed to create symlink: %s: %w", target, err)
			}
		case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
			if err := copyDevice(target, fi); err != nil {
				return fmt.Errorf("failed to create device: %w", err)
			}
		default:
			// TODO: Support pipes and sockets
			if err != nil {
				return fmt.Errorf("unsupported mode %s: %w", fi.Mode(), err)
			}
		}

		if err := copyFileInfo(fi, source, target); err != nil {
			return fmt.Errorf("failed to copy file info: %w", err)
		}

		if err := copyXAttrs(target, source, o.xex, o.xeh); err != nil {
			return fmt.Errorf("failed to copy xattrs: %w", err)
		}
	}

	return nil
}

// CopyFile copies the source file to the target.
// The most efficient means of copying is used for the platform.
func CopyFile(target, source string) error {
	src, err := os.Open(source)
	if err != nil {
		return fmt.Errorf("failed to open source %s: %w", source, err)
	}
	defer src.Close()
	tgt, err := os.Create(target)
	if err != nil {
		return fmt.Errorf("failed to open target %s: %w", target, err)
	}
	defer tgt.Close()

	return copyFileContent(tgt, src)
}
<|endoftext|>


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

// A collection of tests for a file system where we do not attempt to write to
// the file system at all. Rather we set up contents in a GCS bucket out of
// band, wait for them to be available, and then read them via the file system.

package fs_test

import (
	"os"
	"path"
	"syscall"

	"github.com/jacobsa/fuse/fusetesting"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

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

type ImplicitDirsTest struct {
	fsTest
}

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

func (t *ImplicitDirsTest) SetUp(ti *TestInfo) {
	t.serverCfg.ImplicitDirectories = true
	t.fsTest.SetUp(ti)
}

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

func (t *ImplicitDirsTest) NothingPresent() {
	// ReadDir
	entries, err := fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)

	ExpectThat(entries, ElementsAre())
}

func (t *ImplicitDirsTest) FileObjectPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",
			}))

	// Statting the name should return an entry for the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectEq(4, fi.Size())
	ExpectFalse(fi.IsDir())

	// ReadDir should show the file.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(4, fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) DirectoryObjectPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// Directory
				"foo/": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ImplicitDirectory_DefinedByFile() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ImplicitDirectory_DefinedByDirectory() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar/": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_PlaceholderPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",

				// Directory
				"foo/": "",
			}))

	// A listing of the parent should contain a directory named "foo" and a
	// file named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(filePerms, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_PlaceholderNotPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",

				// Implicit directory
				"foo/bar": "",
			}))

	// A listing of the parent should contain a directory named "foo" and a
	// file named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(filePerms, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_OneIsSymlink() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// Symlink
				"foo": "",

				// Directory
				"foo/": "",
			}))

	// Cause "foo" to look like a symlink.
	err = setSymlinkTarget(t.ctx, t.bucket, "foo", "")
	AssertEq(nil, err)

	// A listing of the parent should contain a directory named "foo" and a
	// symlink named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(filePerms|os.ModeSymlink, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Lstat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the symlink.
	fi, err = os.Lstat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(filePerms|os.ModeSymlink, fi.Mode())
}

func (t *ImplicitDirsTest) StatUnknownName_NoOtherContents() {
	var err error

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) StatUnknownName_UnrelatedContents() {
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"bar": "",
				"baz": "",
			}))

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) StatUnknownName_PrefixOfActualNames() {
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foop":  "",
				"fooq/": "",
			}))

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) ImplicitBecomesExplicit() {
	var fi os.FileInfo
	var err error

	// Set up an implicit directory.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar": "",
			}))

	// Stat it.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Set up an explicit placeholder.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/": "",
			}))

	// Stat the directory again.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ExplicitBecomesImplicit() {
	var fi os.FileInfo
	var err error

	// Set up an explicit directory.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/":    "",
				"foo/bar": "",
			}))

	// Stat it.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Remove the explicit placeholder.
	AssertEq(nil, t.bucket.DeleteObject(t.ctx, "foo/"))

	// Stat the directory again.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) Rmdir_NotEmpty_OnlyImplicit() {
	AssertTrue(false, "TODO")
}

func (t *ImplicitDirsTest) Rmdir_NotEmpty_ImplicitAndExplicit() {
	AssertTrue(false, "TODO")
}

func (t *ImplicitDirsTest) Rmdir_Empty_OnlyImplicit() {
	AssertTrue(false, "TODO")
}

func (t *ImplicitDirsTest) Rmdir_Empty_ImplicitAndExplicit() {
	AssertTrue(false, "TODO")
}
<commit_msg>ImplicitDirsTest.Rmdir_NotEmpty_OnlyImplicit<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A collection of tests for a file system where we do not attempt to write to
// the file system at all. Rather we set up contents in a GCS bucket out of
// band, wait for them to be available, and then read them via the file system.

package fs_test

import (
	"os"
	"path"
	"syscall"

	"github.com/jacobsa/fuse/fusetesting"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
)

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

type ImplicitDirsTest struct {
	fsTest
}

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

func (t *ImplicitDirsTest) SetUp(ti *TestInfo) {
	t.serverCfg.ImplicitDirectories = true
	t.fsTest.SetUp(ti)
}

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

func (t *ImplicitDirsTest) NothingPresent() {
	// ReadDir
	entries, err := fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)

	ExpectThat(entries, ElementsAre())
}

func (t *ImplicitDirsTest) FileObjectPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",
			}))

	// Statting the name should return an entry for the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectEq(4, fi.Size())
	ExpectFalse(fi.IsDir())

	// ReadDir should show the file.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(4, fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) DirectoryObjectPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// Directory
				"foo/": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ImplicitDirectory_DefinedByFile() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ImplicitDirectory_DefinedByDirectory() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar/": "",
			}))

	// Statting the name should return an entry for the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// ReadDir should show the directory.
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(1, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_PlaceholderPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",

				// Directory
				"foo/": "",
			}))

	// A listing of the parent should contain a directory named "foo" and a
	// file named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(filePerms, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_PlaceholderNotPresent() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// File
				"foo": "taco",

				// Implicit directory
				"foo/bar": "",
			}))

	// A listing of the parent should contain a directory named "foo" and a
	// file named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(len("taco"), fi.Size())
	ExpectEq(filePerms, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the file.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(len("taco"), fi.Size())
	ExpectFalse(fi.IsDir())
}

func (t *ImplicitDirsTest) ConflictingNames_OneIsSymlink() {
	var fi os.FileInfo
	var entries []os.FileInfo
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				// Symlink
				"foo": "",

				// Directory
				"foo/": "",
			}))

	// Cause "foo" to look like a symlink.
	err = setSymlinkTarget(t.ctx, t.bucket, "foo", "")
	AssertEq(nil, err)

	// A listing of the parent should contain a directory named "foo" and a
	// symlink named "foo\n".
	entries, err = fusetesting.ReadDirPicky(t.mfs.Dir())
	AssertEq(nil, err)
	AssertEq(2, len(entries))

	fi = entries[0]
	ExpectEq("foo", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(dirPerms|os.ModeDir, fi.Mode())
	ExpectTrue(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	fi = entries[1]
	ExpectEq("foo\n", fi.Name())
	ExpectEq(0, fi.Size())
	ExpectEq(filePerms|os.ModeSymlink, fi.Mode())
	ExpectFalse(fi.IsDir())
	ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink)

	// Statting "foo" should yield the directory.
	fi, err = os.Lstat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Statting "foo\n" should yield the symlink.
	fi, err = os.Lstat(path.Join(t.mfs.Dir(), "foo\n"))
	AssertEq(nil, err)

	ExpectEq("foo\n", fi.Name())
	ExpectEq(filePerms|os.ModeSymlink, fi.Mode())
}

func (t *ImplicitDirsTest) StatUnknownName_NoOtherContents() {
	var err error

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) StatUnknownName_UnrelatedContents() {
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"bar": "",
				"baz": "",
			}))

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) StatUnknownName_PrefixOfActualNames() {
	var err error

	// Set up contents.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foop":  "",
				"fooq/": "",
			}))

	// Stat an unknown name.
	_, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	ExpectTrue(os.IsNotExist(err), "err: %v", err)
}

func (t *ImplicitDirsTest) ImplicitBecomesExplicit() {
	var fi os.FileInfo
	var err error

	// Set up an implicit directory.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar": "",
			}))

	// Stat it.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Set up an explicit placeholder.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/": "",
			}))

	// Stat the directory again.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) ExplicitBecomesImplicit() {
	var fi os.FileInfo
	var err error

	// Set up an explicit directory.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/":    "",
				"foo/bar": "",
			}))

	// Stat it.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())

	// Remove the explicit placeholder.
	AssertEq(nil, t.bucket.DeleteObject(t.ctx, "foo/"))

	// Stat the directory again.
	fi, err = os.Stat(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) Rmdir_NotEmpty_OnlyImplicit() {
	var err error

	// Set up an implicit directory.
	AssertEq(
		nil,
		t.createObjects(
			map[string]string{
				"foo/bar": "",
			}))

	// Attempt to remove it.
	err = os.Remove(path.Join(t.Dir, "foo"))

	AssertNe(nil, err)
	ExpectThat(err, Error(HasSubstr("not empty")))

	// It should still be there.
	fi, err := os.Lstat(path.Join(t.Dir, "foo"))

	AssertEq(nil, err)
	ExpectEq("foo", fi.Name())
	ExpectTrue(fi.IsDir())
}

func (t *ImplicitDirsTest) Rmdir_NotEmpty_ImplicitAndExplicit() {
	AssertTrue(false, "TODO")
}

func (t *ImplicitDirsTest) Rmdir_Empty_OnlyImplicit() {
	AssertTrue(false, "TODO")
}

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


<commit_before>package fscache

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"
)

// Cache works like a concurrent-safe map for streams.
type Cache interface {

	// Get manages access to the streams in the cache.
	// If the key does not exist, w != nil and you can start writing to the stream.
	// If the key does exist, w == nil.
	// r will always be non-nil as long as err == nil and you must close r when you're done reading.
	// Get can be called concurrently, and writing and reading is concurrent safe.
	Get(key string) (ReaderAtCloser, io.WriteCloser, error)

	// Remove deletes the stream from the cache, blocking until the underlying
	// file can be deleted (all active streams finish with it).
	// It is safe to call Remove concurrently with Get.
	Remove(key string) error

	// Exists checks if a key is in the cache.
	// It is safe to call Exists concurrently with Get.
	Exists(key string) bool

	// Clean will empty the cache and delete the cache folder.
	// Clean is not safe to call while streams are being read/written.
	Clean() error
}

type cache struct {
	mu    sync.RWMutex
	files map[string]fileStream
	grim  Reaper
	fs    FileSystem
}

type ReaderAtCloser interface {
	io.ReadCloser
	io.ReaderAt
}

type fileStream interface {
	next() (ReaderAtCloser, error)
	inUse() bool
	io.WriteCloser
	Remove() error
	Name() string
}

// New creates a new Cache using NewFs(dir, perms).
// expiry is the duration after which an un-accessed key will be removed from
// the cache, a zero value expiro means never expire.
func New(dir string, perms os.FileMode, expiry time.Duration) (Cache, error) {
	fs, err := NewFs(dir, perms)
	if err != nil {
		return nil, err
	}
	var grim Reaper
	if expiry > 0 {
		grim = &reaper{
			expiry: expiry,
			period: expiry,
		}
	}
	return NewCache(fs, grim)
}

// NewCache creates a new Cache based on FileSystem fs.
// fs.Files() are loaded using the name they were created with as a key.
// Reaper is used to determine when files expire, nil means never expire.
func NewCache(fs FileSystem, grim Reaper) (Cache, error) {
	c := &cache{
		files: make(map[string]fileStream),
		grim:  grim,
		fs:    fs,
	}
	err := c.load()
	if err != nil {
		return nil, err
	}
	if grim != nil {
		c.haunter()
	}
	return c, nil
}

func (c *cache) haunter() {
	c.haunt()
	time.AfterFunc(c.grim.Next(), c.haunter)
}

func (c *cache) haunt() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, f := range c.files {
		if f.inUse() {
			continue
		}

		lastRead, lastWrite, err := c.fs.AccessTimes(f.Name())
		if err != nil {
			continue
		}

		if c.grim.Reap(key, lastRead, lastWrite) {
			delete(c.files, key)
			c.fs.Remove(f.Name())
		}
	}
	return
}

func (c *cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.fs.Reload(func(key, name string) {
		c.files[key] = c.oldFile(name)
	})
}

func (c *cache) Exists(key string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	_, ok := c.files[key]
	return ok
}

func (c *cache) Get(key string) (r ReaderAtCloser, w io.WriteCloser, err error) {
	c.mu.RLock()
	f, ok := c.files[key]
	if ok {
		r, err = f.next()
		c.mu.RUnlock()
		return r, nil, err
	}
	c.mu.RUnlock()

	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok = c.files[key]
	if ok {
		r, err = f.next()
		return r, nil, err
	}

	f, err = c.newFile(key)
	if err != nil {
		return nil, nil, err
	}

	r, err = f.next()
	if err != nil {
		f.Close()
		c.fs.Remove(f.Name())
		return nil, nil, err
	}

	c.files[key] = f

	return r, f, err
}

func (c *cache) Remove(key string) error {
	c.mu.Lock()
	f, ok := c.files[key]
	delete(c.files, key)
	c.mu.Unlock()

	if ok {
		return f.Remove()
	}
	return nil
}

func (c *cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]fileStream)
	return c.fs.RemoveAll()
}

type cachedFile struct {
	stream *stream.Stream
	handleCounter
}

func (c *cache) newFile(name string) (fileStream, error) {
	s, err := stream.NewStream(name, c.fs)
	if err != nil {
		return nil, err
	}
	cf := &cachedFile{
		stream: s,
	}
	cf.inc()
	return cf, nil
}

func (c *cache) oldFile(name string) fileStream {
	return &reloadedFile{
		fs:   c.fs,
		name: name,
	}
}

type reloadedFile struct {
	fs   FileSystem
	name string
	handleCounter
	io.WriteCloser // nop Write & Close methods. will never be called.
}

func (f *reloadedFile) Name() string { return f.name }

func (f *reloadedFile) Remove() error {
	f.waitUntilFree()
	return f.fs.Remove(f.name)
}

func (f *reloadedFile) next() (r ReaderAtCloser, err error) {
	r, err = f.fs.Open(f.name)
	if err == nil {
		f.inc()
	}
	return &cacheReader{r: r, cnt: &f.handleCounter}, err
}

func (f *cachedFile) Name() string { return f.stream.Name() }

func (f *cachedFile) Remove() error { return f.stream.Remove() }

func (f *cachedFile) next() (r ReaderAtCloser, err error) {
	reader, err := f.stream.NextReader()
	if err != nil {
		return nil, err
	}
	f.inc()
	return &cacheReader{
		r:   reader,
		cnt: &f.handleCounter,
	}, nil
}

func (f *cachedFile) Write(p []byte) (int, error) {
	return f.stream.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.dec()
	return f.stream.Close()
}

type cacheReader struct {
	r   ReaderAtCloser
	cnt *handleCounter
}

func (r *cacheReader) ReadAt(p []byte, off int64) (n int, err error) {
	return r.r.ReadAt(p, off)
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	return r.r.Read(p)
}

func (r *cacheReader) Close() error {
	defer r.cnt.dec()
	return r.r.Close()
}

type handleCounter struct {
	cnt int64
	sync.WaitGroup
}

func (h *handleCounter) inc() {
	h.grp.Add(1)
	atomic.AddInt64(&h.cnt, 1)
}

func (h *handleCounter) dec() {
	atomic.AddInt64(&h.cnt, -1)
	h.grp.Done()
}

func (h *handleCounter) inUse() bool {
	return atomic.LoadInt64(&h.cnt) > 0
}

func (h *handleCounter) waitUntilFree() {
	h.grp.Wait()
}
<commit_msg>fixed auto-removed imports<commit_after>package fscache

import (
	"io"
	"os"
	"sync"
	"sync/atomic"
	"time"

	"gopkg.in/djherbis/atime.v1"
	"gopkg.in/djherbis/stream.v1"
)

// Cache works like a concurrent-safe map for streams.
type Cache interface {

	// Get manages access to the streams in the cache.
	// If the key does not exist, w != nil and you can start writing to the stream.
	// If the key does exist, w == nil.
	// r will always be non-nil as long as err == nil and you must close r when you're done reading.
	// Get can be called concurrently, and writing and reading is concurrent safe.
	Get(key string) (ReaderAtCloser, io.WriteCloser, error)

	// Remove deletes the stream from the cache, blocking until the underlying
	// file can be deleted (all active streams finish with it).
	// It is safe to call Remove concurrently with Get.
	Remove(key string) error

	// Exists checks if a key is in the cache.
	// It is safe to call Exists concurrently with Get.
	Exists(key string) bool

	// Clean will empty the cache and delete the cache folder.
	// Clean is not safe to call while streams are being read/written.
	Clean() error
}

type cache struct {
	mu    sync.RWMutex
	files map[string]fileStream
	grim  Reaper
	fs    FileSystem
}

type ReaderAtCloser interface {
	io.ReadCloser
	io.ReaderAt
}

type fileStream interface {
	next() (ReaderAtCloser, error)
	inUse() bool
	io.WriteCloser
	Remove() error
	Name() string
}

// New creates a new Cache using NewFs(dir, perms).
// expiry is the duration after which an un-accessed key will be removed from
// the cache, a zero value expiro means never expire.
func New(dir string, perms os.FileMode, expiry time.Duration) (Cache, error) {
	fs, err := NewFs(dir, perms)
	if err != nil {
		return nil, err
	}
	var grim Reaper
	if expiry > 0 {
		grim = &reaper{
			expiry: expiry,
			period: expiry,
		}
	}
	return NewCache(fs, grim)
}

// NewCache creates a new Cache based on FileSystem fs.
// fs.Files() are loaded using the name they were created with as a key.
// Reaper is used to determine when files expire, nil means never expire.
func NewCache(fs FileSystem, grim Reaper) (Cache, error) {
	c := &cache{
		files: make(map[string]fileStream),
		grim:  grim,
		fs:    fs,
	}
	err := c.load()
	if err != nil {
		return nil, err
	}
	if grim != nil {
		c.haunter()
	}
	return c, nil
}

func (c *cache) haunter() {
	c.haunt()
	time.AfterFunc(c.grim.Next(), c.haunter)
}

func (c *cache) haunt() {
	c.mu.Lock()
	defer c.mu.Unlock()

	for key, f := range c.files {
		if f.inUse() {
			continue
		}

		lastRead, lastWrite, err := c.fs.AccessTimes(f.Name())
		if err != nil {
			continue
		}

		if c.grim.Reap(key, lastRead, lastWrite) {
			delete(c.files, key)
			c.fs.Remove(f.Name())
		}
	}
	return
}

func (c *cache) load() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	return c.fs.Reload(func(key, name string) {
		c.files[key] = c.oldFile(name)
	})
}

func (c *cache) Exists(key string) bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	_, ok := c.files[key]
	return ok
}

func (c *cache) Get(key string) (r ReaderAtCloser, w io.WriteCloser, err error) {
	c.mu.RLock()
	f, ok := c.files[key]
	if ok {
		r, err = f.next()
		c.mu.RUnlock()
		return r, nil, err
	}
	c.mu.RUnlock()

	c.mu.Lock()
	defer c.mu.Unlock()

	f, ok = c.files[key]
	if ok {
		r, err = f.next()
		return r, nil, err
	}

	f, err = c.newFile(key)
	if err != nil {
		return nil, nil, err
	}

	r, err = f.next()
	if err != nil {
		f.Close()
		c.fs.Remove(f.Name())
		return nil, nil, err
	}

	c.files[key] = f

	return r, f, err
}

func (c *cache) Remove(key string) error {
	c.mu.Lock()
	f, ok := c.files[key]
	delete(c.files, key)
	c.mu.Unlock()

	if ok {
		return f.Remove()
	}
	return nil
}

func (c *cache) Clean() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	c.files = make(map[string]fileStream)
	return c.fs.RemoveAll()
}

type cachedFile struct {
	stream *stream.Stream
	handleCounter
}

func (c *cache) newFile(name string) (fileStream, error) {
	s, err := stream.NewStream(name, c.fs)
	if err != nil {
		return nil, err
	}
	cf := &cachedFile{
		stream: s,
	}
	cf.inc()
	return cf, nil
}

func (c *cache) oldFile(name string) fileStream {
	return &reloadedFile{
		fs:   c.fs,
		name: name,
	}
}

type reloadedFile struct {
	fs   FileSystem
	name string
	handleCounter
	io.WriteCloser // nop Write & Close methods. will never be called.
}

func (f *reloadedFile) Name() string { return f.name }

func (f *reloadedFile) Remove() error {
	f.waitUntilFree()
	return f.fs.Remove(f.name)
}

func (f *reloadedFile) next() (r ReaderAtCloser, err error) {
	r, err = f.fs.Open(f.name)
	if err == nil {
		f.inc()
	}
	return &cacheReader{r: r, cnt: &f.handleCounter}, err
}

func (f *cachedFile) Name() string { return f.stream.Name() }

func (f *cachedFile) Remove() error { return f.stream.Remove() }

func (f *cachedFile) next() (r ReaderAtCloser, err error) {
	reader, err := f.stream.NextReader()
	if err != nil {
		return nil, err
	}
	f.inc()
	return &cacheReader{
		r:   reader,
		cnt: &f.handleCounter,
	}, nil
}

func (f *cachedFile) Write(p []byte) (int, error) {
	return f.stream.Write(p)
}

func (f *cachedFile) Close() error {
	defer f.dec()
	return f.stream.Close()
}

type cacheReader struct {
	r   ReaderAtCloser
	cnt *handleCounter
}

func (r *cacheReader) ReadAt(p []byte, off int64) (n int, err error) {
	return r.r.ReadAt(p, off)
}

func (r *cacheReader) Read(p []byte) (n int, err error) {
	return r.r.Read(p)
}

func (r *cacheReader) Close() error {
	defer r.cnt.dec()
	return r.r.Close()
}

type handleCounter struct {
	cnt int64
	sync.WaitGroup
}

func (h *handleCounter) inc() {
	h.grp.Add(1)
	atomic.AddInt64(&h.cnt, 1)
}

func (h *handleCounter) dec() {
	atomic.AddInt64(&h.cnt, -1)
	h.grp.Done()
}

func (h *handleCounter) inUse() bool {
	return atomic.LoadInt64(&h.cnt) > 0
}

func (h *handleCounter) waitUntilFree() {
	h.grp.Wait()
}
<|endoftext|>


<commit_before>package bouncermain

import (
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/op/go-logging"
)

var logger = logging.MustGetLogger("bouncer")

var decoder = newDecoder()

var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{level:.4s} %{id:03x}%{color:reset} %{message}",
)

func setupLogging() {
	backend1 := logging.NewLogBackend(os.Stdout, "", 0)
	backend1Formatter := logging.NewBackendFormatter(backend1, format)
	backend1Leveled := logging.AddModuleLevel(backend1Formatter)

	logging.SetBackend(backend1Leveled)
}

func Main() {
	runtime.LockOSThread()
	setupLogging()

	logger.Info("Starting...")

	server := &http.Server{
		Addr:         ":8080",
		Handler:      Router(),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	logger.Fatal(server.ListenAndServe())

}
<commit_msg>Modify default port to 5505<commit_after>package bouncermain

import (
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/op/go-logging"
)

var logger = logging.MustGetLogger("bouncer")

var decoder = newDecoder()

var format = logging.MustStringFormatter(
	"%{color}%{time:15:04:05.000} %{level:.4s} %{id:03x}%{color:reset} %{message}",
)

func setupLogging() {
	backend1 := logging.NewLogBackend(os.Stdout, "", 0)
	backend1Formatter := logging.NewBackendFormatter(backend1, format)
	backend1Leveled := logging.AddModuleLevel(backend1Formatter)

	logging.SetBackend(backend1Leveled)
}

func Main() {
	runtime.LockOSThread()
	setupLogging()

	logger.Info("Starting...")

	server := &http.Server{
		Addr:         ":5505",
		Handler:      Router(),
		ReadTimeout:  10 * time.Second,
		WriteTimeout: 10 * time.Second,
	}

	logger.Fatal(server.ListenAndServe())

}
<|endoftext|>


<commit_before>package main

import (
	"math/rand"
	"time"
)

const (
	HEIGHT       = 80
	WIDTH        = 180
	UPDATELENGTH = 30000
	ALIVE        = '*'
	DEAD         = ' '
)

var (
	board         = [HEIGHT][WIDTH]int{}
	weightedarray = [10]int{0, 0, 0, 0, 0, 0, 0, 1, 1}
)

func genBoard(board [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			board[x][y] = weightedarray[rand.Intn(10)]
		}
	}
}

func copyBoard(newB [HEIGHT][WIDTH]int, oldB [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			newB[x][y] = oldB[x][y]
		}
	}
}

func updateBoard(board [HEIGHT][WIDTH]int) {
	var next_board [HEIGHT][WIDTH]int
	copyBoard(next_board, board)
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			aliveN := 0
			neighbours := []int{
				board[x-1][y+1],
				board[x][y+1],
				board[x+1][y+1],
				board[x+1][y],
				board[x+1][y-1],
				board[x][y-1],
				board[x-1][y-1],
				board[x-1][y],
			}

			for _, cell := range neighbours {
				if cell > 0 {
					aliveN++
				}
			}
			/*
			  Rules
			  =====

			  1. Any live cell with fewer than two live neighbours
			  dies, as if caused by under-population.

			  2. Any live cell with two or three live neighbours lives
			  on to the next generation.

			  3. Any live cell with more than three live neighbours
			  dies, as if by overcrowding.

			  4. Any dead cell with exactly three live neighbours
			  becomes a live cell, as if by reproduction.
			*/
			if board[x][y] == 1 && aliveN < 2 {
				next_board[x][y] = 0
				continue
			}
			if board[x][y] == 1 && (aliveN == 2 || aliveN == 3) {
				continue
			}
			if board[x][y] == 1 && aliveN > 3 {
				next_board[x][y] = 0
				continue
			}
			if board[x][y] != 1 && aliveN == 3 {
				next_board[x][y] = 1
				continue
			}
		}
	}
	copyBoard(board, next_board)
}

func drawBoard(board [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			if board[x][y] == 0 {
			} else {
			}
		}
	}
}

func main() {
	genBoard(board)
	for {
		time.Sleep(10000)
		updateBoard(board)
		drawBoard(board)
	}
}
<commit_msg>Draw the board at the right time.<commit_after>package main

import (
	"fmt"
	"math/rand"
	"time"
)

const (
	HEIGHT       = 80
	WIDTH        = 180
	UPDATELENGTH = 30000
	ALIVE        = '*'
	DEAD         = ' '
)

var (
	board         = [HEIGHT][WIDTH]int{}
	weightedarray = [10]int{0, 0, 0, 0, 0, 0, 0, 1, 1}
)

func genBoard(board [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			board[x][y] = weightedarray[rand.Intn(10)]
		}
	}
}

func copyBoard(newB [HEIGHT][WIDTH]int, oldB [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			newB[x][y] = oldB[x][y]
		}
	}
}

func updateBoard(board [HEIGHT][WIDTH]int) {
	var next_board [HEIGHT][WIDTH]int
	copyBoard(next_board, board)
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			aliveN := 0
			neighbours := []int{
				board[x-1][y+1],
				board[x][y+1],
				board[x+1][y+1],
				board[x+1][y],
				board[x+1][y-1],
				board[x][y-1],
				board[x-1][y-1],
				board[x-1][y],
			}

			for _, cell := range neighbours {
				if cell > 0 {
					aliveN++
				}
			}
			/*
			  Rules
			  =====

			  1. Any live cell with fewer than two live neighbours
			  dies, as if caused by under-population.

			  2. Any live cell with two or three live neighbours lives
			  on to the next generation.

			  3. Any live cell with more than three live neighbours
			  dies, as if by overcrowding.

			  4. Any dead cell with exactly three live neighbours
			  becomes a live cell, as if by reproduction.
			*/
			if board[x][y] == 1 && aliveN < 2 {
				next_board[x][y] = 0
				continue
			}
			if board[x][y] == 1 && (aliveN == 2 || aliveN == 3) {
				continue
			}
			if board[x][y] == 1 && aliveN > 3 {
				next_board[x][y] = 0
				continue
			}
			if board[x][y] != 1 && aliveN == 3 {
				next_board[x][y] = 1
				continue
			}
		}
	}
	copyBoard(board, next_board)
}

func drawBoard(board [HEIGHT][WIDTH]int) {
	for x := 0; x < HEIGHT; x++ {
		for y := 0; y < WIDTH; y++ {
			if board[x][y] == 0 {
				fmt.Print("0")
			} else {
				fmt.Print("X")
			}
		}
		fmt.Println()
	}
}

func main() {
	genBoard(board)
	drawBoard(board)
	for {
		time.Sleep(10000)
		updateBoard(board)
		drawBoard(board)
	}
}
<|endoftext|>


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

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 4
	// Patch is the curernt patched version of the master branch.
	Patch = 2
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "dev"
)
<commit_msg>Promote to 4.3 stable<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	// Major is the current major version of master branch.
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 4
	// Patch is the curernt patched version of the master branch.
	Patch = 3
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "stable"
)
<|endoftext|>


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

package version

var (
	// Major is the current major version of master branch..
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 1
	// Patch is the curernt patched version of the master branch.
	Patch = 0
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "stable"
)
<commit_msg>Start work on 0.1.1 dev<commit_after>// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package version

var (
	// Major is the current major version of master branch..
	Major = 0
	// Minor is the current minor version of master branch.
	Minor = 1
	// Patch is the curernt patched version of the master branch.
	Patch = 1
	// Release is the current release level of the master branch. Valid values
	// are dev (developement unreleased), rcX (release candidate with current
	// iteration), stable (indicates a final released version).
	Release = "dev"
)
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

const (
	ADD_SERVICE    = "http://localhost:3000/api/v1/service/add"
	RUN_CONTAINER  = "http://localhost:3000/api/v1/container/run"
	LIST_CONTAINER = "http://localhost:3000/api/v1/container/list"
	EXEC_CONTAINER = "http://localhost:3000/api/v1/container/exec"
	STOP_CONTAINER = "http://localhost:3000/api/v1/container/stop"
)

func call(url string) {
	if len(os.Args) != 4 {
		help()
		return
	}

	filename := os.Args[3]

	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 201 {
		body, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(string(body))
	}
}

func listContainers() {
	resp, err := http.Get(LIST_CONTAINER)
	if err != nil {
		fmt.Println(err)
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(body))
}

func execContainer() {
	if len(os.Args) <= 4 {
		help()
		return
	}

	raw := []byte(fmt.Sprintf("{\"name\":\"%s\"}", os.Args[3]))
	fmt.Println(string(raw))
	req, err := http.NewRequest("POST", EXEC_CONTAINER, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	pid := string(body)
	cmd := strings.Join(os.Args[4:], " ")
	path, err := exec.LookPath("nsenter")
	if err != nil {
		fmt.Println("Cannot find nsenter")
		return
	}

	command := strings.Split(fmt.Sprintf("%s --target %s --pid --net --mount %s", path, pid, cmd), " ")
	run := &exec.Cmd{
		Path: command[0],
		Args: command,
	}

	run.Stdin = os.Stdin
	run.Stdout = os.Stdout
	run.Stderr = os.Stderr
	run.Start()
	run.Wait()
}

func stopContainer() {
	if len(os.Args) != 4 {
		help()
		return
	}

	raw := []byte(fmt.Sprintf("{\"name\":\"%s\"}", os.Args[3]))
	fmt.Println(string(raw))
	req, err := http.NewRequest("POST", STOP_CONTAINER, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}

func help() {
	fmt.Println("Commands:")
	fmt.Println("\tcontainer")
	fmt.Println("\tservice")
	fmt.Println()

	fmt.Println("container:")
	fmt.Println("\trun filename.json - Runs command specified in filename.json")
	fmt.Println("\texec container_hash command... - Runs specified command in container")
	fmt.Println("\tlist - Lists all running containers")
	fmt.Println("\tstop container_hash - Stops container")
	fmt.Println()

	fmt.Println("service:")
	fmt.Println("\tadd filename.json - Creates a service with details from filename.json")
}

func main() {
	if len(os.Args) < 3 {
		help()
		return
	}

	switch os.Args[1] {
	case "service":
		switch os.Args[2] {
		case "add":
			call(ADD_SERVICE)
		default:
			help()
		}
	case "container":
		switch os.Args[2] {
		case "run":
			call(RUN_CONTAINER)
		case "list":
			listContainers()
		case "exec":
			execContainer()
		case "stop":
			stopContainer()
		default:
			help()
		}
	default:
		help()
	}
}
<commit_msg>Pretty print<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/bpowell/brocker/container"
)

const (
	ADD_SERVICE    = "http://localhost:3000/api/v1/service/add"
	RUN_CONTAINER  = "http://localhost:3000/api/v1/container/run"
	LIST_CONTAINER = "http://localhost:3000/api/v1/container/list"
	EXEC_CONTAINER = "http://localhost:3000/api/v1/container/exec"
	STOP_CONTAINER = "http://localhost:3000/api/v1/container/stop"
)

func call(url string) {
	if len(os.Args) != 4 {
		help()
		return
	}

	filename := os.Args[3]

	raw, err := ioutil.ReadFile(filename)
	if err != nil {
		fmt.Println(err)
		return
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 201 {
		body, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(string(body))
	}
}

func listContainers() {
	resp, err := http.Get(LIST_CONTAINER)
	if err != nil {
		fmt.Println(err)
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	var containers []container.Container
	if err := json.Unmarshal(body, &containers); err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println("Name\t\tTime started\t\t\tRunning\tService Name\t\tCommand")
	for _, c := range containers {
		fmt.Printf("%s\t%s\t%t\t%s\t\t%s\n", c.Name, c.StartTime.Format(time.UnixDate), c.Active, c.ServiceName, c.Command)
	}
}

func execContainer() {
	if len(os.Args) <= 4 {
		help()
		return
	}

	raw := []byte(fmt.Sprintf("{\"name\":\"%s\"}", os.Args[3]))
	fmt.Println(string(raw))
	req, err := http.NewRequest("POST", EXEC_CONTAINER, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	pid := string(body)
	cmd := strings.Join(os.Args[4:], " ")
	path, err := exec.LookPath("nsenter")
	if err != nil {
		fmt.Println("Cannot find nsenter")
		return
	}

	command := strings.Split(fmt.Sprintf("%s --target %s --pid --net --mount %s", path, pid, cmd), " ")
	run := &exec.Cmd{
		Path: command[0],
		Args: command,
	}

	run.Stdin = os.Stdin
	run.Stdout = os.Stdout
	run.Stderr = os.Stderr
	run.Start()
	run.Wait()
}

func stopContainer() {
	if len(os.Args) != 4 {
		help()
		return
	}

	raw := []byte(fmt.Sprintf("{\"name\":\"%s\"}", os.Args[3]))
	fmt.Println(string(raw))
	req, err := http.NewRequest("POST", STOP_CONTAINER, bytes.NewBuffer(raw))
	req.Header.Set("Content-Type", "application/json")
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}

func help() {
	fmt.Println("Commands:")
	fmt.Println("\tcontainer")
	fmt.Println("\tservice")
	fmt.Println()

	fmt.Println("container:")
	fmt.Println("\trun filename.json - Runs command specified in filename.json")
	fmt.Println("\texec container_hash command... - Runs specified command in container")
	fmt.Println("\tlist - Lists all running containers")
	fmt.Println("\tstop container_hash - Stops container")
	fmt.Println()

	fmt.Println("service:")
	fmt.Println("\tadd filename.json - Creates a service with details from filename.json")
}

func main() {
	if len(os.Args) < 3 {
		help()
		return
	}

	switch os.Args[1] {
	case "service":
		switch os.Args[2] {
		case "add":
			call(ADD_SERVICE)
		default:
			help()
		}
	case "container":
		switch os.Args[2] {
		case "run":
			call(RUN_CONTAINER)
		case "list":
			listContainers()
		case "exec":
			execContainer()
		case "stop":
			stopContainer()
		default:
			help()
		}
	default:
		help()
	}
}
<|endoftext|>


<commit_before>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// Cross-compiles gh
//
// Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	t.Log("Removing build target...")
	err = os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	t.Log("Cross-compiling gh...")
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<commit_msg>Add task to cross compile on darwin and linux<commit_after>// +build gotask

package main

import (
	"github.com/jingweno/gotask/tasking"
	"os"
	"runtime"
)

// Cross-compiles gh for all supported platforms.
//
// Cross-compiles gh for all supported platforms. The build artifacts
// will be in target/VERSION. This only works on darwin with Vagrant setup.
func TaskCrossCompileAll(t *tasking.T) {
	t.Log("Removing build target...")
	err := os.RemoveAll("target")
	if err != nil {
		t.Errorf("Can't remove build target: %s\n", err)
		return
	}

	// for darwin
	t.Log("Compiling for darwin...")
	TaskCrossCompile(t)
	if t.Failed() {
		return
	}

	// for linux
	t.Log("Compiling for linux...")
	err = t.Exec("vagrant ssh -c 'cd ~/src/github.com/jingweno/gh && git pull origin master && gotask cross-compile'")
	if err != nil {
		t.Errorf("Can't compile on linux: %s\n", err)
		return
	}
}

// Cross-compiles gh for current operating system.
//
// Cross-compiles gh for current operating system. The build artifacts will be in target/VERSION
func TaskCrossCompile(t *tasking.T) {
	t.Log("Updating goxc...")
	err := t.Exec("go get -u github.com/laher/goxc")
	if err != nil {
		t.Errorf("Can't update goxc: %s\n", err)
		return
	}

	t.Log("Cross-compiling gh for mac...")
	err = t.Exec("goxc", "-wd=.", "-os="+runtime.GOOS, "-c="+runtime.GOOS)
	if err != nil {
		t.Errorf("Can't cross-compile gh: %s\n", err)
		return
	}
}
<|endoftext|>


<commit_before>package cmd

// Version is the current version of the buffalo binary
var Version = "0.4.6"
<commit_msg>version bump<commit_after>package cmd

// Version is the current version of the buffalo binary
var Version = "0.4.7"
<|endoftext|>


<commit_before>package igc

import (
	"bufio"
	"fmt"
	"github.com/twpayne/gogeom/geom"
	"io"
	"strconv"
	"strings"
	"time"
)

type Errors map[int]error

func (es Errors) Error() string {
	ss := make([]string, len(es))
	for i, e := range es {
		ss[i] = e.Error()
	}
	return strings.Join(ss, "\n")
}

func parseDec(s string, start, stop int) (int, error) {
	result := 0
	for i := start; i < stop; i++ {
		if c := s[i]; '0' <= c && c <= '9' {
			result = 10*result + int(c) - '0'
		} else {
			return 0, fmt.Errorf("invalid")
		}
	}
	return result, nil
}

type parser struct {
	pointMs          []geom.PointM
	year, month, day int
}

func newParser() *parser {
	p := new(parser)
	p.year = 2000
	p.month = 1
	p.day = 1
	return p
}

func (p *parser) parseB(line string) error {
	var err error
	var hour, minute, second int
	if hour, err = strconv.Atoi(line[1:3]); err != nil {
		return err
	}
	if minute, err = strconv.Atoi(line[3:5]); err != nil {
		return err
	}
	if second, err = strconv.Atoi(line[5:7]); err != nil {
		return err
	}
	var latDeg, latMin int
	if latDeg, err = strconv.Atoi(line[7:9]); err != nil {
		return err
	}
	if latMin, err = strconv.Atoi(line[9:14]); err != nil {
		return err
	}
	lat := float64(latDeg) + float64(latMin)/60000.
	switch c := line[14]; c {
	case 'N':
	case 'S':
		lat = -lat
	default:
		return fmt.Errorf("unexpected character %v", c)
	}
	var lngDeg, lngMin int
	lngDeg, err = strconv.Atoi(line[15:18])
	if err != nil {
		return err
	}
	lngMin, err = strconv.Atoi(line[18:23])
	if err != nil {
		return err
	}
	lng := float64(lngDeg) + float64(lngMin)/60000.
	switch c := line[23]; c {
	case 'E':
	case 'W':
		lng = -lng
	default:
		return fmt.Errorf("unexpected character %v", c)
	}
	date := time.Date(p.year, time.Month(p.month), p.day, hour, minute, second, 0, time.UTC)
	pointM := geom.PointM{lng, lat, float64(date.UnixNano()) / 1e9}
	p.pointMs = append(p.pointMs, pointM)
	return nil
}

func (p *parser) parseH(line string) error {
	switch {
	case strings.HasPrefix(line, "HFDTE"):
		return p.parseHFDTE(line)
	default:
		return nil
	}
}

func (p *parser) parseHFDTE(line string) error {
	var err error
	var day, month, year int
	if day, err = strconv.Atoi(line[5:7]); err != nil {
		return err
	}
	if month, err = strconv.Atoi(line[7:9]); err != nil {
		return err
	}
	if year, err = strconv.Atoi(line[9:11]); err != nil {
		return err
	}
	// FIXME check for invalid dates
	p.day = day
	p.month = month
	if year < 70 {
		p.year = 2000 + year
	} else {
		p.year = 1970 + year
	}
	return nil
}

func (p *parser) parseLine(line string) error {
	switch line[0] {
	case 'B':
		return p.parseB(line)
	case 'H':
		return p.parseH(line)
	default:
		return nil
	}
}

func Read(r io.Reader) ([]geom.PointM, error) {
	errors := make(Errors)
	p := newParser()
	s := bufio.NewScanner(r)
	line := 0
	for s.Scan() {
		line++
		if err := p.parseLine(s.Text()); err != nil {
			errors[line] = err
		}
	}
	if len(errors) == 0 {
		return p.pointMs, nil
	} else {
		return p.pointMs, errors
	}
}
<commit_msg>Use parseDec instead of strconv.Atoi<commit_after>package igc

import (
	"bufio"
	"fmt"
	"github.com/twpayne/gogeom/geom"
	"io"
	"strings"
	"time"
)

type Errors map[int]error

func (es Errors) Error() string {
	ss := make([]string, len(es))
	for i, e := range es {
		ss[i] = e.Error()
	}
	return strings.Join(ss, "\n")
}

func parseDec(s string, start, stop int) (int, error) {
	result := 0
	for i := start; i < stop; i++ {
		if c := s[i]; '0' <= c && c <= '9' {
			result = 10*result + int(c) - '0'
		} else {
			return 0, fmt.Errorf("invalid")
		}
	}
	return result, nil
}

type parser struct {
	pointMs          []geom.PointM
	year, month, day int
}

func newParser() *parser {
	p := new(parser)
	p.year = 2000
	p.month = 1
	p.day = 1
	return p
}

func (p *parser) parseB(line string) error {
	var err error
	var hour, minute, second int
	if hour, err = parseDec(line, 1, 3); err != nil {
		return err
	}
	if minute, err = parseDec(line, 3, 5); err != nil {
		return err
	}
	if second, err = parseDec(line, 5, 7); err != nil {
		return err
	}
	var latDeg, latMin int
	if latDeg, err = parseDec(line, 7, 9); err != nil {
		return err
	}
	if latMin, err = parseDec(line, 9, 14); err != nil {
		return err
	}
	lat := float64(latDeg) + float64(latMin)/60000.
	switch c := line[14]; c {
	case 'N':
	case 'S':
		lat = -lat
	default:
		return fmt.Errorf("unexpected character %v", c)
	}
	var lngDeg, lngMin int
	lngDeg, err = parseDec(line, 15, 18)
	if err != nil {
		return err
	}
	lngMin, err = parseDec(line, 18, 23)
	if err != nil {
		return err
	}
	lng := float64(lngDeg) + float64(lngMin)/60000.
	switch c := line[23]; c {
	case 'E':
	case 'W':
		lng = -lng
	default:
		return fmt.Errorf("unexpected character %v", c)
	}
	date := time.Date(p.year, time.Month(p.month), p.day, hour, minute, second, 0, time.UTC)
	pointM := geom.PointM{lng, lat, float64(date.UnixNano()) / 1e9}
	p.pointMs = append(p.pointMs, pointM)
	return nil
}

func (p *parser) parseH(line string) error {
	switch {
	case strings.HasPrefix(line, "HFDTE"):
		return p.parseHFDTE(line)
	default:
		return nil
	}
}

func (p *parser) parseHFDTE(line string) error {
	var err error
	var day, month, year int
	if day, err = parseDec(line, 5, 7); err != nil {
		return err
	}
	if month, err = parseDec(line, 7, 9); err != nil {
		return err
	}
	if year, err = parseDec(line, 9, 11); err != nil {
		return err
	}
	// FIXME check for invalid dates
	p.day = day
	p.month = month
	if year < 70 {
		p.year = 2000 + year
	} else {
		p.year = 1970 + year
	}
	return nil
}

func (p *parser) parseLine(line string) error {
	switch line[0] {
	case 'B':
		return p.parseB(line)
	case 'H':
		return p.parseH(line)
	default:
		return nil
	}
}

func Read(r io.Reader) ([]geom.PointM, error) {
	errors := make(Errors)
	p := newParser()
	s := bufio.NewScanner(r)
	line := 0
	for s.Scan() {
		line++
		if err := p.parseLine(s.Text()); err != nil {
			errors[line] = err
		}
	}
	if len(errors) == 0 {
		return p.pointMs, nil
	} else {
		return p.pointMs, errors
	}
}
<|endoftext|>


<commit_before>package search_test

import (
	"fmt"
	"math"
	"testing"

	"github.com/gonum/graph"
	"github.com/gonum/graph/concrete"
	"github.com/gonum/graph/search"
	//	"github.com/gonum/graph/set"
)

func TestSimpleAStar(t *testing.T) {
	tg, err := concrete.GenerateTileGraph("▀  ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀")
	if err != nil {
		t.Fatal("Couldn't generate tilegraph")
	}

	path, cost, _ := search.AStar(concrete.GonumNode(1), concrete.GonumNode(14), tg, nil, nil)
	if math.Abs(cost-4.0) > .00001 {
		t.Errorf("A* reports incorrect cost for simple tilegraph search")
	}

	if path == nil {
		t.Fatalf("A* fails to find path for for simple tilegraph search")
	} else {
		correctPath := []int{1, 2, 6, 10, 14}
		if len(path) != len(correctPath) {
			t.Fatalf("Astar returns wrong length path for simple tilegraph search")
		}
		for i, node := range path {
			if node.ID() != correctPath[i] {
				t.Errorf("Astar returns wrong path at step", i, "got:", node, "actual:", correctPath[i])
			}
		}
	}
}

func TestBiggerAStar(t *testing.T) {
	tg := concrete.NewTileGraph(3, 3, true)

	path, cost, _ := search.AStar(concrete.GonumNode(0), concrete.GonumNode(8), tg, nil, nil)

	if math.Abs(cost-4.0) > .00001 || !search.IsPath(path, tg) {
		t.Error("Non-optimal or impossible path found for 3x3 grid")
	}

	tg = concrete.NewTileGraph(1000, 1000, true)
	path, cost, _ = search.AStar(concrete.GonumNode(00), concrete.GonumNode(999*1000+999), tg, nil, nil)
	if !search.IsPath(path, tg) || cost != 1998.0 {
		t.Error("Non-optimal or impossible path found for 100x100 grid; cost:", cost, "path:\n"+tg.PathString(path))
	}
}

func TestObstructedAStar(t *testing.T) {
	tg := concrete.NewTileGraph(10, 10, true)

	// Creates a partial "wall" down the middle row with a gap down the left side
	tg.SetPassability(4, 1, false)
	tg.SetPassability(4, 2, false)
	tg.SetPassability(4, 3, false)
	tg.SetPassability(4, 4, false)
	tg.SetPassability(4, 5, false)
	tg.SetPassability(4, 6, false)
	tg.SetPassability(4, 7, false)
	tg.SetPassability(4, 8, false)
	tg.SetPassability(4, 9, false)

	rows, cols := tg.Dimensions()
	path, cost1, expanded := search.AStar(concrete.GonumNode(5), tg.CoordsToNode(rows-1, cols-1), tg, nil, nil)

	if !search.IsPath(path, tg) {
		t.Error("Path doesn't exist in obstructed graph")
	}

	ManhattanHeuristic := func(n1, n2 graph.Node) float64 {
		id1, id2 := n1.ID(), n2.ID()
		r1, c1 := tg.IDToCoords(id1)
		r2, c2 := tg.IDToCoords(id2)

		return math.Abs(float64(r1)-float64(r2)) + math.Abs(float64(c1)-float64(c2))
	}

	path, cost2, expanded2 := search.AStar(concrete.GonumNode(5), tg.CoordsToNode(rows-1, cols-1), tg, nil, ManhattanHeuristic)
	if !search.IsPath(path, tg) {
		t.Error("Path doesn't exist when using heuristic on obstructed graph")
	}

	if math.Abs(cost1-cost2) > .00001 {
		t.Error("Cost when using admissible heuristic isn't approximately equal to cost without it")
	}

	if expanded2 > expanded {
		t.Error("Using admissible, consistent heuristic expanded more nodes than null heuristic (possible, but unlikely -- suggests an error somewhere)")
	}

}

func TestNoPathAStar(t *testing.T) {
	tg := concrete.NewTileGraph(5, 5, true)

	// Creates a "wall" down the middle row
	tg.SetPassability(2, 0, false)
	tg.SetPassability(2, 1, false)
	tg.SetPassability(2, 2, false)
	tg.SetPassability(2, 3, false)
	tg.SetPassability(2, 4, false)

	rows, _ := tg.Dimensions()
	path, _, _ := search.AStar(tg.CoordsToNode(0, 2), tg.CoordsToNode(rows-1, 2), tg, nil, nil)

	if len(path) > 0 { // Note that a nil slice will return len of 0, this won't panic
		t.Error("A* finds path where none exists")
	}
}

func TestSmallAStar(t *testing.T) {
	gg := newSmallGonumGraph()
	heur := newSmallHeuristic()
	if ok, edge, goal := monotonic(gg, heur); !ok {
		t.Fatalf("non-monotonic heuristic.  edge: %v goal: %v", edge, goal)
	}
	for _, start := range gg.NodeList() {
		// get reference paths by Dijkstra
		dPaths, dCosts := search.Dijkstra(start, gg, nil)
		// assert that AStar finds each path
		for goalID, dPath := range dPaths {
			exp := fmt.Sprintln(dPath, dCosts[goalID])
			aPath, aCost, work := search.AStar(start, concrete.GonumNode(goalID), gg, nil, heur)
			fmt.Println()
			got := fmt.Sprintln(aPath, aCost)
			if got != exp {
				t.Error("expected", exp, "got", got)
			}
			t.Log(aPath, work)
		}
	}
}

func ExampleBreadthFirstSearch() {
	g := concrete.NewGonumGraph(true)
	var n0, n1, n2, n3 concrete.GonumNode = 0, 1, 2, 3
	g.AddNode(n0, []graph.Node{n1, n2})
	g.AddEdge(concrete.GonumEdge{n2, n3})
	path, v := search.BreadthFirstSearch(n0, n3, g)
	fmt.Println("path:", path)
	fmt.Println("nodes visited:", v)
	// Output:
	// path: [0 2 3]
	// nodes visited: 4
}

func newSmallGonumGraph() *concrete.GonumGraph {
	eds := []struct{ n1, n2, edgeCost int }{
		{1, 2, 7},
		{1, 3, 9},
		{1, 6, 14},
		{2, 3, 10},
		{2, 4, 15},
		{3, 4, 11},
		{3, 6, 2},
		{4, 5, 7},
		{5, 6, 9},
	}
	g := concrete.NewGonumGraph(false)
	for n := concrete.GonumNode(1); n <= 6; n++ {
		g.AddNode(n, nil)
	}
	for _, ed := range eds {
		e := concrete.GonumEdge{
			concrete.GonumNode(ed.n1),
			concrete.GonumNode(ed.n2),
		}
		g.AddEdge(e)
		g.SetEdgeCost(e, float64(ed.edgeCost))
	}
	return g
}

func newSmallHeuristic() func(n1, n2 graph.Node) float64 {
	nds := []struct{ id, x, y int }{
		{1, 0, 6},
		{2, 1, 0},
		{3, 8, 7},
		{4, 16, 0},
		{5, 17, 6},
		{6, 9, 8},
	}
	return func(n1, n2 graph.Node) float64 {
		i1 := n1.ID() - 1
		i2 := n2.ID() - 1
		dx := nds[i2].x - nds[i1].x
		dy := nds[i2].y - nds[i1].y
		return math.Hypot(float64(dx), float64(dy))
	}
}

func monotonic(g graph.CostGraph, heur func(n1, n2 graph.Node) float64) (bool, graph.Edge, graph.Node) {
	for _, goal := range g.NodeList() {
		for _, edge := range g.EdgeList() {
			head := edge.Head()
			tail := edge.Tail()
			if heur(head, goal) > g.Cost(head, tail)+heur(tail, goal) {
				return false, edge, goal
			}
		}
	}
	return true, nil, nil
}

// Test for correct result on a small graph easily solvable by hand
func TestDijkstraSmall(t *testing.T) {
	g := newSmallGonumGraph()
	paths, lens := search.Dijkstra(concrete.GonumNode(1), g, nil)
	s := fmt.Sprintln(len(paths), len(lens))
	for i := 1; i <= 6; i++ {
		s += fmt.Sprintln(paths[i], lens[i])
	}
	if s != `6 6
[1] 0
[1 2] 7
[1 3] 9
[1 3 4] 20
[1 3 6 5] 20
[1 3 6] 11
` {
		t.Fatal(s)
	}
}
<commit_msg>clean up output<commit_after>package search_test

import (
	"fmt"
	"math"
	"testing"

	"github.com/gonum/graph"
	"github.com/gonum/graph/concrete"
	"github.com/gonum/graph/search"
	//	"github.com/gonum/graph/set"
)

func TestSimpleAStar(t *testing.T) {
	tg, err := concrete.GenerateTileGraph("▀  ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀")
	if err != nil {
		t.Fatal("Couldn't generate tilegraph")
	}

	path, cost, _ := search.AStar(concrete.GonumNode(1), concrete.GonumNode(14), tg, nil, nil)
	if math.Abs(cost-4.0) > .00001 {
		t.Errorf("A* reports incorrect cost for simple tilegraph search")
	}

	if path == nil {
		t.Fatalf("A* fails to find path for for simple tilegraph search")
	} else {
		correctPath := []int{1, 2, 6, 10, 14}
		if len(path) != len(correctPath) {
			t.Fatalf("Astar returns wrong length path for simple tilegraph search")
		}
		for i, node := range path {
			if node.ID() != correctPath[i] {
				t.Errorf("Astar returns wrong path at step", i, "got:", node, "actual:", correctPath[i])
			}
		}
	}
}

func TestBiggerAStar(t *testing.T) {
	tg := concrete.NewTileGraph(3, 3, true)

	path, cost, _ := search.AStar(concrete.GonumNode(0), concrete.GonumNode(8), tg, nil, nil)

	if math.Abs(cost-4.0) > .00001 || !search.IsPath(path, tg) {
		t.Error("Non-optimal or impossible path found for 3x3 grid")
	}

	tg = concrete.NewTileGraph(1000, 1000, true)
	path, cost, _ = search.AStar(concrete.GonumNode(00), concrete.GonumNode(999*1000+999), tg, nil, nil)
	if !search.IsPath(path, tg) || cost != 1998.0 {
		t.Error("Non-optimal or impossible path found for 100x100 grid; cost:", cost, "path:\n"+tg.PathString(path))
	}
}

func TestObstructedAStar(t *testing.T) {
	tg := concrete.NewTileGraph(10, 10, true)

	// Creates a partial "wall" down the middle row with a gap down the left side
	tg.SetPassability(4, 1, false)
	tg.SetPassability(4, 2, false)
	tg.SetPassability(4, 3, false)
	tg.SetPassability(4, 4, false)
	tg.SetPassability(4, 5, false)
	tg.SetPassability(4, 6, false)
	tg.SetPassability(4, 7, false)
	tg.SetPassability(4, 8, false)
	tg.SetPassability(4, 9, false)

	rows, cols := tg.Dimensions()
	path, cost1, expanded := search.AStar(concrete.GonumNode(5), tg.CoordsToNode(rows-1, cols-1), tg, nil, nil)

	if !search.IsPath(path, tg) {
		t.Error("Path doesn't exist in obstructed graph")
	}

	ManhattanHeuristic := func(n1, n2 graph.Node) float64 {
		id1, id2 := n1.ID(), n2.ID()
		r1, c1 := tg.IDToCoords(id1)
		r2, c2 := tg.IDToCoords(id2)

		return math.Abs(float64(r1)-float64(r2)) + math.Abs(float64(c1)-float64(c2))
	}

	path, cost2, expanded2 := search.AStar(concrete.GonumNode(5), tg.CoordsToNode(rows-1, cols-1), tg, nil, ManhattanHeuristic)
	if !search.IsPath(path, tg) {
		t.Error("Path doesn't exist when using heuristic on obstructed graph")
	}

	if math.Abs(cost1-cost2) > .00001 {
		t.Error("Cost when using admissible heuristic isn't approximately equal to cost without it")
	}

	if expanded2 > expanded {
		t.Error("Using admissible, consistent heuristic expanded more nodes than null heuristic (possible, but unlikely -- suggests an error somewhere)")
	}

}

func TestNoPathAStar(t *testing.T) {
	tg := concrete.NewTileGraph(5, 5, true)

	// Creates a "wall" down the middle row
	tg.SetPassability(2, 0, false)
	tg.SetPassability(2, 1, false)
	tg.SetPassability(2, 2, false)
	tg.SetPassability(2, 3, false)
	tg.SetPassability(2, 4, false)

	rows, _ := tg.Dimensions()
	path, _, _ := search.AStar(tg.CoordsToNode(0, 2), tg.CoordsToNode(rows-1, 2), tg, nil, nil)

	if len(path) > 0 { // Note that a nil slice will return len of 0, this won't panic
		t.Error("A* finds path where none exists")
	}
}

func TestSmallAStar(t *testing.T) {
	gg := newSmallGonumGraph()
	heur := newSmallHeuristic()
	if ok, edge, goal := monotonic(gg, heur); !ok {
		t.Fatalf("non-monotonic heuristic.  edge: %v goal: %v", edge, goal)
	}
	for _, start := range gg.NodeList() {
		// get reference paths by Dijkstra
		dPaths, dCosts := search.Dijkstra(start, gg, nil)
		// assert that AStar finds each path
		for goalID, dPath := range dPaths {
			exp := fmt.Sprintln(dPath, dCosts[goalID])
			aPath, aCost, _ := search.AStar(start, concrete.GonumNode(goalID), gg, nil, heur)
			got := fmt.Sprintln(aPath, aCost)
			if got != exp {
				t.Error("expected", exp, "got", got)
			}
		}
	}
}

func ExampleBreadthFirstSearch() {
	g := concrete.NewGonumGraph(true)
	var n0, n1, n2, n3 concrete.GonumNode = 0, 1, 2, 3
	g.AddNode(n0, []graph.Node{n1, n2})
	g.AddEdge(concrete.GonumEdge{n2, n3})
	path, v := search.BreadthFirstSearch(n0, n3, g)
	fmt.Println("path:", path)
	fmt.Println("nodes visited:", v)
	// Output:
	// path: [0 2 3]
	// nodes visited: 4
}

func newSmallGonumGraph() *concrete.GonumGraph {
	eds := []struct{ n1, n2, edgeCost int }{
		{1, 2, 7},
		{1, 3, 9},
		{1, 6, 14},
		{2, 3, 10},
		{2, 4, 15},
		{3, 4, 11},
		{3, 6, 2},
		{4, 5, 7},
		{5, 6, 9},
	}
	g := concrete.NewGonumGraph(false)
	for n := concrete.GonumNode(1); n <= 6; n++ {
		g.AddNode(n, nil)
	}
	for _, ed := range eds {
		e := concrete.GonumEdge{
			concrete.GonumNode(ed.n1),
			concrete.GonumNode(ed.n2),
		}
		g.AddEdge(e)
		g.SetEdgeCost(e, float64(ed.edgeCost))
	}
	return g
}

func newSmallHeuristic() func(n1, n2 graph.Node) float64 {
	nds := []struct{ id, x, y int }{
		{1, 0, 6},
		{2, 1, 0},
		{3, 8, 7},
		{4, 16, 0},
		{5, 17, 6},
		{6, 9, 8},
	}
	return func(n1, n2 graph.Node) float64 {
		i1 := n1.ID() - 1
		i2 := n2.ID() - 1
		dx := nds[i2].x - nds[i1].x
		dy := nds[i2].y - nds[i1].y
		return math.Hypot(float64(dx), float64(dy))
	}
}

func monotonic(g graph.CostGraph, heur func(n1, n2 graph.Node) float64) (bool, graph.Edge, graph.Node) {
	for _, goal := range g.NodeList() {
		for _, edge := range g.EdgeList() {
			head := edge.Head()
			tail := edge.Tail()
			if heur(head, goal) > g.Cost(head, tail)+heur(tail, goal) {
				return false, edge, goal
			}
		}
	}
	return true, nil, nil
}

// Test for correct result on a small graph easily solvable by hand
func TestDijkstraSmall(t *testing.T) {
	g := newSmallGonumGraph()
	paths, lens := search.Dijkstra(concrete.GonumNode(1), g, nil)
	s := fmt.Sprintln(len(paths), len(lens))
	for i := 1; i <= 6; i++ {
		s += fmt.Sprintln(paths[i], lens[i])
	}
	if s != `6 6
[1] 0
[1 2] 7
[1 3] 9
[1 3 4] 20
[1 3 6 5] 20
[1 3 6] 11
` {
		t.Fatal(s)
	}
}
<|endoftext|>