<commit_before>package matching_test

import (
	"testing"

	"github.com/SpectoLabs/hoverfly/core/matching"
	. "github.com/onsi/gomega"
)

func Test_ExactMatch_MatchesTrueWithExactMatch(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch("yes", "yes")).To(BeTrue())
}

func Test_ExactMatch_MatchesFalseWithIncorrectExactMatch(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch("yes", "no")).To(BeFalse())
}
<commit_msg>Added tests around matching json with ExactMatch<commit_after>package matching_test

import (
	"testing"

	"github.com/SpectoLabs/hoverfly/core/matching"
	. "github.com/onsi/gomega"
)

func Test_ExactMatch_MatchesTrueWithExactMatch(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch("yes", "yes")).To(BeTrue())
}

func Test_ExactMatch_MatchesFalseWithIncorrectExactMatch(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch("yes", "no")).To(BeFalse())
}

func Test_ExactMatch_MatchesTrueWithJSON(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch(`{"test":{"json":true,"minified":true}}`, `{"test":{"json":true,"minified":true}}`)).To(BeTrue())
}

func Test_ExactMatch_MatchesTrueWithUnminifiedJSON(t *testing.T) {
	RegisterTestingT(t)

	Expect(matching.ExactMatch(`{"test":{"json":true,"minified":true}}`, `{
		"test": {
			"json": true,
			"minified":
			true
		}
	}`)).To(BeFalse())
}
<|endoftext|>


<commit_before>package main

import (
	"archive/tar"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/kr/pty"
	"github.com/mattn/go-shellwords"
	"github.com/pivotal-golang/archiver/compressor"
	"github.com/pkg/term"

	"github.com/cloudfoundry-incubator/garden"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

func handleComplete(c *cli.Context) {
	// This will complete if no args are passed
	if len(c.Args()) > 0 {
		return
	}

	containers, err := client(c).Containers(nil)
	failIf(err)

	for _, container := range containers {
		fmt.Println(container.Handle())
	}
}

func fail(err error) {
	fmt.Fprintln(os.Stderr, "failed:", err)
	os.Exit(1)
}

func failIf(err error) {
	if err != nil {
		fail(err)
	}
}

func client(c *cli.Context) garden.Client {
	target := c.GlobalString("target")
	return gclient.New(gconn.New("tcp", target))
}

func handle(c *cli.Context) string {
	if len(c.Args()) == 0 {
		fail(errors.New("must provide container handle"))
	}
	return c.Args().First()
}

func main() {
	app := cli.NewApp()
	app.Name = "gaol"
	app.Usage = "a cli for garden"
	app.Version = "0.0.1"
	app.Author = "Chris Brown"
	app.Email = "cbrown@pivotal.io"
	app.EnableBashCompletion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "target, t",
			Value:  "localhost:7777",
			Usage:  "server to which commands are sent",
			EnvVar: "GAOL_TARGET",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:  "ping",
			Usage: "check if the server is running",
			Action: func(c *cli.Context) {
				err := client(c).Ping()
				failIf(err)
			},
		},
		{
			Name:  "create",
			Usage: "create a container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "handle, n",
					Usage: "name to give container",
				},
				cli.StringFlag{
					Name:  "rootfs, r",
					Usage: "rootfs image with which to create the container",
				},
				cli.DurationFlag{
					Name:  "grace, g",
					Usage: "grace time (resetting ttl) of container",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "privileged user in container is privileged in host",
				},
			},
			Action: func(c *cli.Context) {
				handle := c.String("handle")
				grace := c.Duration("grace")
				rootfs := c.String("rootfs")
				privileged := c.Bool("privileged")

				container, err := client(c).Create(garden.ContainerSpec{
					Handle:     handle,
					GraceTime:  grace,
					RootFSPath: rootfs,
					Privileged: privileged,
				})
				failIf(err)

				fmt.Println(container.Handle())
			},
		},
		{
			Name:         "destroy",
			Usage:        "destroy a container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				client := client(c)
				handles := c.Args()

				for _, handle := range handles {
					err := client.Destroy(handle)
					failIf(err)
				}
			},
		},
		{
			Name:  "list",
			Usage: "get a list of running containers",
			Action: func(c *cli.Context) {
				containers, err := client(c).Containers(nil)
				failIf(err)

				for _, container := range containers {
					fmt.Println(container.Handle())
				}
			},
		},
		{
			Name:  "run",
			Usage: "run a command in a container",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "attach, a",
					Usage: "attach to the process after it is started",
				},
				cli.StringFlag{
					Name:  "dir, d",
					Usage: "current working directory of process",
				},
				cli.StringFlag{
					Name:  "user, u",
					Usage: "user to run the process as",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "use privileged user in container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				attach := c.Bool("attach")
				dir := c.String("dir")
				user := c.String("user")
				privileged := c.Bool("privileged")

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				var processIo garden.ProcessIO
				if attach {
					processIo = garden.ProcessIO{
						Stdin:  os.Stdin,
						Stdout: os.Stdout,
						Stderr: os.Stderr,
					}
				} else {
					processIo = garden.ProcessIO{}
				}

				command := c.Args()[1]
				args, err := shellwords.Parse(command)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path:       args[0],
					Args:       args[1:],
					Dir:        dir,
					Privileged: privileged,
					User:       user,
				}, processIo)
				failIf(err)

				if attach {
					process.Wait()
				} else {
					fmt.Println(process.ID())
				}
			},
		},
		{
			Name:         "shell",
			Usage:        "open a shell inside the running container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				container, err := client(c).Lookup(handle(c))
				failIf(err)

				term, err := term.Open(os.Stdin.Name())
				failIf(err)

				err = term.SetRaw()
				failIf(err)

				rows, cols, err := pty.Getsize(os.Stdin)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path: "/bin/sh",
					Args: []string{"-l"},
					Env:  []string{"TERM=" + os.Getenv("TERM")},
					TTY: &garden.TTYSpec{
						WindowSize: &garden.WindowSize{
							Rows:    rows,
							Columns: cols,
						},
					},
					Privileged: true,
				}, garden.ProcessIO{
					Stdin:  term,
					Stdout: term,
					Stderr: term,
				})
				if err != nil {
					term.Restore()
					failIf(err)
				}

				resized := make(chan os.Signal, 10)
				signal.Notify(resized, syscall.SIGWINCH)

				go func() {
					for {
						<-resized

						rows, cols, err := pty.Getsize(os.Stdin)
						if err == nil {
							process.SetTTY(garden.TTYSpec{
								WindowSize: &garden.WindowSize{
									Rows:    rows,
									Columns: cols,
								},
							})
						}
					}
				}()

				process.Wait()
				term.Restore()
			},
		},
		{
			Name:  "stream-in",
			Usage: "stream data into the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "to-file, t",
					Usage: "destination path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				dst := c.String("to-file")
				if dst == "" {
					fail(errors.New("missing --to-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				// perform dance to get correct file names
				tmpDir, err := ioutil.TempDir("", "gaol")
				failIf(err)
				defer os.RemoveAll(tmpDir)

				tmp, err := os.Create(filepath.Join(tmpDir, filepath.Base(dst)))
				failIf(err)

				_, err = io.Copy(tmp, os.Stdin)
				failIf(err)

				err = tmp.Close()
				failIf(err)

				reader, writer := io.Pipe()
				go func(w io.WriteCloser) {
					err := compressor.WriteTar(tmp.Name(), w)
					failIf(err)
					w.Close()
				}(writer)

				err = container.StreamIn(filepath.Dir(dst), reader)
				failIf(err)
			},
		},
		{
			Name:  "stream-out",
			Usage: "stream data out of the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from-file, f",
					Usage: "source path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				src := c.String("from-file")
				if src == "" {
					fail(errors.New("missing --from-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				output, err := container.StreamOut(src)
				failIf(err)

				tr := tar.NewReader(output)
				_, err = tr.Next()
				failIf(err)

				_, err = io.Copy(os.Stdout, tr)
				failIf(err)
			},
		},
	}

	app.Run(os.Args)
}
<commit_msg>add attach command<commit_after>package main

import (
	"archive/tar"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/kr/pty"
	"github.com/mattn/go-shellwords"
	"github.com/pivotal-golang/archiver/compressor"
	"github.com/pkg/term"

	"github.com/cloudfoundry-incubator/garden"
	gclient "github.com/cloudfoundry-incubator/garden/client"
	gconn "github.com/cloudfoundry-incubator/garden/client/connection"
)

func handleComplete(c *cli.Context) {
	// This will complete if no args are passed
	if len(c.Args()) > 0 {
		return
	}

	containers, err := client(c).Containers(nil)
	failIf(err)

	for _, container := range containers {
		fmt.Println(container.Handle())
	}
}

func fail(err error) {
	fmt.Fprintln(os.Stderr, "failed:", err)
	os.Exit(1)
}

func failIf(err error) {
	if err != nil {
		fail(err)
	}
}

func client(c *cli.Context) garden.Client {
	target := c.GlobalString("target")
	return gclient.New(gconn.New("tcp", target))
}

func handle(c *cli.Context) string {
	if len(c.Args()) == 0 {
		fail(errors.New("must provide container handle"))
	}
	return c.Args().First()
}

func main() {
	app := cli.NewApp()
	app.Name = "gaol"
	app.Usage = "a cli for garden"
	app.Version = "0.0.1"
	app.Author = "Chris Brown"
	app.Email = "cbrown@pivotal.io"
	app.EnableBashCompletion = true

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "target, t",
			Value:  "localhost:7777",
			Usage:  "server to which commands are sent",
			EnvVar: "GAOL_TARGET",
		},
	}

	app.Commands = []cli.Command{
		{
			Name:  "ping",
			Usage: "check if the server is running",
			Action: func(c *cli.Context) {
				err := client(c).Ping()
				failIf(err)
			},
		},
		{
			Name:  "create",
			Usage: "create a container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "handle, n",
					Usage: "name to give container",
				},
				cli.StringFlag{
					Name:  "rootfs, r",
					Usage: "rootfs image with which to create the container",
				},
				cli.DurationFlag{
					Name:  "grace, g",
					Usage: "grace time (resetting ttl) of container",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "privileged user in container is privileged in host",
				},
			},
			Action: func(c *cli.Context) {
				handle := c.String("handle")
				grace := c.Duration("grace")
				rootfs := c.String("rootfs")
				privileged := c.Bool("privileged")

				container, err := client(c).Create(garden.ContainerSpec{
					Handle:     handle,
					GraceTime:  grace,
					RootFSPath: rootfs,
					Privileged: privileged,
				})
				failIf(err)

				fmt.Println(container.Handle())
			},
		},
		{
			Name:         "destroy",
			Usage:        "destroy a container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				client := client(c)
				handles := c.Args()

				for _, handle := range handles {
					err := client.Destroy(handle)
					failIf(err)
				}
			},
		},
		{
			Name:  "list",
			Usage: "get a list of running containers",
			Action: func(c *cli.Context) {
				containers, err := client(c).Containers(nil)
				failIf(err)

				for _, container := range containers {
					fmt.Println(container.Handle())
				}
			},
		},
		{
			Name:  "run",
			Usage: "run a command in a container",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "attach, a",
					Usage: "attach to the process after it is started",
				},
				cli.StringFlag{
					Name:  "dir, d",
					Usage: "current working directory of process",
				},
				cli.StringFlag{
					Name:  "user, u",
					Usage: "user to run the process as",
				},
				cli.BoolFlag{
					Name:  "privileged, p",
					Usage: "use privileged user in container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				attach := c.Bool("attach")
				dir := c.String("dir")
				user := c.String("user")
				privileged := c.Bool("privileged")

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				var processIo garden.ProcessIO
				if attach {
					processIo = garden.ProcessIO{
						Stdin:  os.Stdin,
						Stdout: os.Stdout,
						Stderr: os.Stderr,
					}
				} else {
					processIo = garden.ProcessIO{}
				}

				command := c.Args()[1]
				args, err := shellwords.Parse(command)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path:       args[0],
					Args:       args[1:],
					Dir:        dir,
					Privileged: privileged,
					User:       user,
				}, processIo)
				failIf(err)

				if attach {
					_, err = process.Wait()
					failIf(err)
				} else {
					fmt.Println(process.ID())
				}
			},
		},
		{
			Name:  "attach",
			Usage: "attach to command running in the container",
			Flags: []cli.Flag{
				cli.IntFlag{
					Name:  "pid, p",
					Usage: "process id to connect to",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				pid := uint32(c.Int("pid"))

				handle := handle(c)
				container, err := client(c).Lookup(handle)
				failIf(err)

				process, err := container.Attach(pid, garden.ProcessIO{
					Stdin:  os.Stdin,
					Stdout: os.Stdout,
					Stderr: os.Stderr,
				})
				failIf(err)

				_, err = process.Wait()
				failIf(err)
			},
		},
		{
			Name:         "shell",
			Usage:        "open a shell inside the running container",
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				container, err := client(c).Lookup(handle(c))
				failIf(err)

				term, err := term.Open(os.Stdin.Name())
				failIf(err)

				err = term.SetRaw()
				failIf(err)

				rows, cols, err := pty.Getsize(os.Stdin)
				failIf(err)

				process, err := container.Run(garden.ProcessSpec{
					Path: "/bin/sh",
					Args: []string{"-l"},
					Env:  []string{"TERM=" + os.Getenv("TERM")},
					TTY: &garden.TTYSpec{
						WindowSize: &garden.WindowSize{
							Rows:    rows,
							Columns: cols,
						},
					},
					Privileged: true,
				}, garden.ProcessIO{
					Stdin:  term,
					Stdout: term,
					Stderr: term,
				})
				if err != nil {
					term.Restore()
					failIf(err)
				}

				resized := make(chan os.Signal, 10)
				signal.Notify(resized, syscall.SIGWINCH)

				go func() {
					for {
						<-resized

						rows, cols, err := pty.Getsize(os.Stdin)
						if err == nil {
							process.SetTTY(garden.TTYSpec{
								WindowSize: &garden.WindowSize{
									Rows:    rows,
									Columns: cols,
								},
							})
						}
					}
				}()

				process.Wait()
				term.Restore()
			},
		},
		{
			Name:  "stream-in",
			Usage: "stream data into the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "to-file, t",
					Usage: "destination path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				dst := c.String("to-file")
				if dst == "" {
					fail(errors.New("missing --to-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				// perform dance to get correct file names
				tmpDir, err := ioutil.TempDir("", "gaol")
				failIf(err)
				defer os.RemoveAll(tmpDir)

				tmp, err := os.Create(filepath.Join(tmpDir, filepath.Base(dst)))
				failIf(err)

				_, err = io.Copy(tmp, os.Stdin)
				failIf(err)

				err = tmp.Close()
				failIf(err)

				reader, writer := io.Pipe()
				go func(w io.WriteCloser) {
					err := compressor.WriteTar(tmp.Name(), w)
					failIf(err)
					w.Close()
				}(writer)

				err = container.StreamIn(filepath.Dir(dst), reader)
				failIf(err)
			},
		},
		{
			Name:  "stream-out",
			Usage: "stream data out of the container",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "from-file, f",
					Usage: "source path in the container",
				},
			},
			BashComplete: handleComplete,
			Action: func(c *cli.Context) {
				handle := handle(c)

				src := c.String("from-file")
				if src == "" {
					fail(errors.New("missing --from-file argument"))
				}

				container, err := client(c).Lookup(handle)
				failIf(err)

				output, err := container.StreamOut(src)
				failIf(err)

				tr := tar.NewReader(output)
				_, err = tr.Next()
				failIf(err)

				_, err = io.Copy(os.Stdout, tr)
				failIf(err)
			},
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>// Packge gdbm implements a wrapper around libgdbm for Go.
package gdbm

// #cgo CFLAGS: -std=gnu99
// #cgo LDFLAGS: -lgdbm
// #include <stdlib.h>
// #include <gdbm.h>
// #include <string.h>
// inline datum mk_datum(char * s) {
//     datum d;
//     d.dptr = s;
//     d.dsize = strlen(s);
//     return d;
// }
import "C"

import (
    "errors"
    "unsafe"
)

//
type Database struct {
    dbf C.GDBM_FILE
    mode int
}

//
type DatabaseCfg struct {
    Mode string
    BlockSize int
    Permissions int
}

func lastError() error {
    return errors.New(C.GoString(C.gdbm_strerror(C.gdbm_errno)))
}

// Simple function to open a database file with default parameters (block size
// is default for the filesystem and file permissions are set to 0666).
func Open(filename string, mode string) (db * Database, err error) {
    return OpenWithCfg(filename, DatabaseCfg{mode, 0, 0666})
}

func OpenWithCfg(filename string, cfg DatabaseCfg) (db * Database, err error) {
    db = new(Database)
    err = nil

    switch cfg.Mode {
    case "r": db.mode = C.GDBM_READER
    case "w": db.mode = C.GDBM_WRITER
    case "c": db.mode = C.GDBM_WRCREAT
    case "n": db.mode = C.GDBM_NEWDB
    }

    cs := C.CString(filename)
    defer C.free(unsafe.Pointer(cs))

    db.dbf = C.gdbm_open(cs, C.int(cfg.BlockSize), C.int(db.mode), C.int(cfg.Permissions), nil)
    if db.dbf == nil {
        err = lastError()
    }
    return db, err
}

// Closes a database file.
func (db * Database) Close() {
    C.gdbm_close(db.dbf)
}

//
func (db * Database) update(key string, value string, flag C.int) (err error) {
    kcs := C.CString(key)
    vcs := C.CString(value)
    k := C.mk_datum(kcs)
    v := C.mk_datum(vcs)
    defer C.free(unsafe.Pointer(kcs))
    defer C.free(unsafe.Pointer(vcs))

    retv := C.gdbm_store(db.dbf, k, v, flag)
    if retv != 0 {
        err = lastError()
    }
    return err
}

//
func (db * Database) Insert(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_INSERT)
}

//
func (db * Database) Replace(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_REPLACE)
}

func (db * Database) Exists(key string) bool {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    e := C.gdbm_exists(db.dbf, k)
    if e == 1 {
        return true
    }
    return false
}

//
func (db * Database) Fetch(key string) (value string, err error) {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    vdatum := C.gdbm_fetch(db.dbf, k)
    if vdatum.dptr == nil {
        return "", lastError()
    }

    value = C.GoString(vdatum.dptr)
    defer C.free(unsafe.Pointer(vdatum.dptr))
    return value, nil
}

//
func (db * Database) Delete(key string) (err error) {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    retv := C.gdbm_delete(db.dbf, k)
    if retv == -1 && db.mode == C.GDBM_READER {
        err = lastError()
    }
    return err
}

//
func (db * Database) Reorganize() {
    C.gdbm_reorganize(db.dbf)
}

//
func (db * Database) Sync() {
    C.gdbm_sync(db.dbf)
}
<commit_msg>Document API<commit_after>// Packge gdbm implements a wrapper around libgdbm, the GNU DataBase Manager
// library, for Go.
package gdbm

// #cgo CFLAGS: -std=gnu99
// #cgo LDFLAGS: -lgdbm
// #include <stdlib.h>
// #include <gdbm.h>
// #include <string.h>
// inline datum mk_datum(char * s) {
//     datum d;
//     d.dptr = s;
//     d.dsize = strlen(s);
//     return d;
// }
import "C"

import (
    "errors"
    "unsafe"
)

// GDBM database "connection" type.
type Database struct {
    dbf C.GDBM_FILE
    mode int
}

// GDBM database configuration type that can be used to specify how the
// database is created and treated. The `Mode` determines what the user of the
// `Database` object can do with it. The field can be a string, either "r" for
// Read-only, "w" for Read-Write, "c" for Read-Write and create if it doesn't
// exist, and "n" for Read-Write and always recreate database, even if it
// exists. TODO: write descriptions for other params... too lazy right now
type DatabaseCfg struct {
    Mode string
    BlockSize int
    Permissions int
}

func lastError() error {
    return errors.New(C.GoString(C.gdbm_strerror(C.gdbm_errno)))
}

// Simple function to open a database file with default parameters (block size
// is default for the filesystem and file permissions are set to 0666).
func Open(filename string, mode string) (db * Database, err error) {
    return OpenWithCfg(filename, DatabaseCfg{mode, 0, 0666})
}

// More complex database initialization function that takes in a `DatabaseCfg`
// struct to allow more fine-grained control over database settings.
func OpenWithCfg(filename string, cfg DatabaseCfg) (db * Database, err error) {
    db = new(Database)

    // Convert a human-readable mode string into a libgdbm-usable constant.
    switch cfg.Mode {
    case "r": db.mode = C.GDBM_READER
    case "w": db.mode = C.GDBM_WRITER
    case "c": db.mode = C.GDBM_WRCREAT
    case "n": db.mode = C.GDBM_NEWDB
    }

    cs := C.CString(filename)
    defer C.free(unsafe.Pointer(cs))
    db.dbf = C.gdbm_open(cs, C.int(cfg.BlockSize), C.int(db.mode), C.int(cfg.Permissions), nil)
    if db.dbf == nil {
        err = lastError()
    }
    return db, err
}

// Closes a database's internal file pointer.
func (db * Database) Close() {
    C.gdbm_close(db.dbf)
}

// Internal helper method to hide the two constants GDBM_INSERT and
// GDBM_REPLACE from the user.
func (db * Database) update(key string, value string, flag C.int) (err error) {
    // Convert key and value into libgdbm's `datum` data structure. See the
    // C definition at the top for the implementation of C.mk_datum(string).
    kcs := C.CString(key)
    vcs := C.CString(value)
    k := C.mk_datum(kcs)
    v := C.mk_datum(vcs)
    defer C.free(unsafe.Pointer(kcs))
    defer C.free(unsafe.Pointer(vcs))

    retv := C.gdbm_store(db.dbf, k, v, flag)
    if retv != 0 {
        err = lastError()
    }
    return err
}

// Inserts a key-value pair into the database. If the database is opened
// in "r" mode, this will return an error. Also, if the key already exists in
// the database, and error will be returned.
func (db * Database) Insert(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_INSERT)
}

// Updates a key-value pair to use a new value, specified by the `value` string
// parameter. An error will be returned if the database is opened in "r" mode.
func (db * Database) Replace(key string, value string) (err error) {
    return db.update(key, value, C.GDBM_REPLACE)
}

// Returns true or false, depending on whether the specified key exists in the
// database.
func (db * Database) Exists(key string) bool {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    e := C.gdbm_exists(db.dbf, k)
    if e == 1 {
        return true
    }
    return false
}

// Fetches the value of the given key. If the key is not in the database, an
// error will be returned in err. Otherwise, value will be the value string
// that is keyed by `key`.
func (db * Database) Fetch(key string) (value string, err error) {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    vdatum := C.gdbm_fetch(db.dbf, k)
    if vdatum.dptr == nil {
        return "", lastError()
    }

    value = C.GoString(vdatum.dptr)
    defer C.free(unsafe.Pointer(vdatum.dptr))
    return value, nil
}

// Removes a key-value pair from the database. If the database is opened in "r"
// mode, an error is returned
func (db * Database) Delete(key string) (err error) {
    kcs := C.CString(key)
    k := C.mk_datum(kcs)
    defer C.free(unsafe.Pointer(kcs))

    retv := C.gdbm_delete(db.dbf, k)
    if retv == -1 && db.mode == C.GDBM_READER {
        err = lastError()
    }
    return err
}

// Reorganizes the database for more efficient use of disk space. This method
// can be used if Delete(k) is called many times.
func (db * Database) Reorganize() {
    C.gdbm_reorganize(db.dbf)
}

// Synchronizes all pending database changes to the disk. TODO: note this is
// only needed in FAST mode, and FAST mode needs implemented!
func (db * Database) Sync() {
    C.gdbm_sync(db.dbf)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
)

func main() {
	var (
		ClientOV    *ov.OVClient
		testName    = "TestFCNetworkGOsdk"
		new_fc_name = "RenamedFCNetwork"
		falseVar    = false
	)

	//To run this example  uncomment below section to fill the ip and the credentials below or use a configuration file
/*		ovc := ClientOV.NewOVClient(
			"ONEVIEW_OV_USER",
			"ONEVIEW_OV_PASSWORD",
			"ONEVIEW_OV_DOMAIN",
			"ONEVIEW_OV_ENDPOINT",
			false,
			<apiversion>,
			"*")*/

	// Use configuratin file to set the ip and  credentails
	config, config_err := ov.LoadConfigFile("oneview_config.json")
	if config_err != nil {
		fmt.Println(config_err)
	}
	ovc := ClientOV.NewOVClient(
		config.UserName,
		config.Password,
		config.Domain,
		config.Endpoint,
		config.SslVerify,
		config.ApiVersion,
		config.IfMatch)

	initialScopeUris := &[]utils.Nstring{utils.NewNstring("/rest/scopes/8ef32b43-2478-4aea-bb68-a65d0fbfea93")}
	fcNetwork := ov.FCNetwork{
		AutoLoginRedistribution: falseVar,
		Description:             "Test FC Network",
		LinkStabilityTime:       30,
		FabricType:              "FabricAttach",
		Name:                    testName,
		Type:                    "fc-networkV4",    //The Type value is for API>500.
		InitialScopeUris:        *initialScopeUris, //added for API>500
	}
	fmt.Println(fcNetwork)
	err := ovc.CreateFCNetwork(fcNetwork)
	if err != nil {
		fmt.Println("Fc Network Creation Failed: ", err)
	} else {
		fmt.Println("Fc Network created successfully...")
	}

	sort := "name:desc"
	fcNetworks, err := ovc.GetFCNetworks("", sort, "", "")
	if err != nil {
		panic(err)
	} else {
		fmt.Println("#---Get Fc Networks sorted by name in descending order----#")
		for i := range fcNetworks.Members {
			fmt.Println(fcNetworks.Members[i].Name)
		}
	}
	fcNetwork2, err := ovc.GetFCNetworkByName(testName)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("#-------------Get FCNetworks by name----------------#")
		fmt.Println(fcNetwork2)
	}
	fcNetwork2.Name = new_fc_name
	err = ovc.UpdateFcNetwork(fcNetwork2)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("FCNetwork has been updated with name: " + fcNetwork2.Name)
	}
	err = ovc.DeleteFCNetwork(new_fc_name)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("Deleted FCNetworks successfully...")
	}

}
<commit_msg>removed strconv import<commit_after>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
)

func main() {
	var (
		ClientOV    *ov.OVClient
		testName    = "TestFCNetworkGOsdk"
		new_fc_name = "RenamedFCNetwork"
		falseVar    = false
	)

	//To run this example  uncomment below section to fill the ip and the credentials below or use a configuration file
	/*		ovc := ClientOV.NewOVClient(
			"ONEVIEW_OV_USER",
			"ONEVIEW_OV_PASSWORD",
			"ONEVIEW_OV_DOMAIN",
			"ONEVIEW_OV_ENDPOINT",
			false,
			<apiversion>,
			"*")*/

	// Use configuratin file to set the ip and  credentails
	config, config_err := ov.LoadConfigFile("oneview_config.json")
	if config_err != nil {
		fmt.Println(config_err)
	}
	ovc := ClientOV.NewOVClient(
		config.UserName,
		config.Password,
		config.Domain,
		config.Endpoint,
		config.SslVerify,
		config.ApiVersion,
		config.IfMatch)

	initialScopeUris := &[]utils.Nstring{utils.NewNstring("/rest/scopes/8ef32b43-2478-4aea-bb68-a65d0fbfea93")}
	fcNetwork := ov.FCNetwork{
		AutoLoginRedistribution: falseVar,
		Description:             "Test FC Network",
		LinkStabilityTime:       30,
		FabricType:              "FabricAttach",
		Name:                    testName,
		Type:                    "fc-networkV4",    //The Type value is for API>500.
		InitialScopeUris:        *initialScopeUris, //added for API>500
	}
	fmt.Println(fcNetwork)
	err := ovc.CreateFCNetwork(fcNetwork)
	if err != nil {
		fmt.Println("Fc Network Creation Failed: ", err)
	} else {
		fmt.Println("Fc Network created successfully...")
	}

	sort := "name:desc"
	fcNetworks, err := ovc.GetFCNetworks("", sort, "", "")
	if err != nil {
		panic(err)
	} else {
		fmt.Println("#---Get Fc Networks sorted by name in descending order----#")
		for i := range fcNetworks.Members {
			fmt.Println(fcNetworks.Members[i].Name)
		}
	}
	fcNetwork2, err := ovc.GetFCNetworkByName(testName)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("#-------------Get FCNetworks by name----------------#")
		fmt.Println(fcNetwork2)
	}
	fcNetwork2.Name = new_fc_name
	err = ovc.UpdateFcNetwork(fcNetwork2)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("FCNetwork has been updated with name: " + fcNetwork2.Name)
	}
	err = ovc.DeleteFCNetwork(new_fc_name)
	if err != nil {
		panic(err)
	} else {
		fmt.Println("Deleted FCNetworks successfully...")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/bugsnag/bugsnag-go"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", Get)

	// Insert your API key
	bugsnag.Configure(bugsnag.Configuration{
		APIKey: "YOUR-API-KEY-HERE",
	})

	log.Println("Serving on 9001")
	http.ListenAndServe(":9001", bugsnag.Handler(nil))
}

func Get(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte("OK\n"))

	var a struct{}
	crash(a)
}

func crash(a interface{}) string {
	return a.(string)
}
<commit_msg>[chore] Update http examples<commit_after>package main

import (
	"log"
	"net/http"
	"os"

	"github.com/bugsnag/bugsnag-go"
)

func main() {
	http.HandleFunc("/unhandled", unhandledCrash)
	http.HandleFunc("/handledError", handledError)

	// Insert your API key
	bugsnag.Configure(bugsnag.Configuration{
		APIKey: "YOUR-API-KEY-HERE",
	})

	log.Println("Serving on 9001")
	http.ListenAndServe(":9001", bugsnag.Handler(nil))
}

func unhandledCrash(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(200)
	w.Write([]byte("OK\n"))

	var a struct{}
	crash(a)
}

func handledError(w http.ResponseWriter, r *http.Request) {
	_, err := os.Open("some_nonexistent_file.txt")
	if err != nil {
		bugsnag.Notify(r.Context(), err)
	}
}

func crash(a interface{}) string {
	return a.(string)
}
<|endoftext|>


<commit_before>package glfw3

// Windows users: If you download the GLFW 64-bit binaries, when you copy over the contents of the lib folder make sure to rename
// glfw3dll.a to libglfw3dll.a, it doesn't work otherwise.

//#cgo windows LDFLAGS: -lglfw3dll -lopengl32 -lgdi32
//#cgo windows CFLAGS: -DGLFW_DLL
//#cgo linux LDFLAGS: -lglfw
//#cgo darwin LDFLAGS: -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo
//#cgo freebsd LDFLAGS: -lglfw3 -lGL -lXrandr -lXxf86vm -lXi
//#include <GLFW/glfw3.h>
import "C"

const (
	VersionMajor    = C.GLFW_VERSION_MAJOR    // This is incremented when the API is changed in non-compatible ways.
	VersionMinor    = C.GLFW_VERSION_MINOR    // This is incremented when features are added to the API but it remains backward-compatible.
	VersionRevision = C.GLFW_VERSION_REVISION // This is incremented when a bug fix release is made that does not contain any API changes.
)

// Init initializes the GLFW library. Before most GLFW functions can be used,
// GLFW must be initialized, and before a program terminates GLFW should be
// terminated in order to free any resources allocated during or after
// initialization.
//
// If this function fails, it calls Terminate before returning. If it succeeds,
// you should call Terminate before the program exits.
//
// Additional calls to this function after successful initialization but before
// termination will succeed but will do nothing.
//
// This function may take several seconds to complete on some systems, while on
// other systems it may take only a fraction of a second to complete.
//
// On Mac OS X, this function will change the current directory of the
// application to the Contents/Resources subdirectory of the application's
// bundle, if present.
//
// This function may only be called from the main thread.
func Init() error {
	if glfwbool(C.glfwInit()) {
		return nil
	}
	return <-lastError
}

// Terminate destroys all remaining windows, frees any allocated resources and
// sets the library to an uninitialized state. Once this is called, you must
// again call Init successfully before you will be able to use most GLFW
// functions.
//
// If GLFW has been successfully initialized, this function should be called
// before the program exits. If initialization fails, there is no need to call
// this function, as it is called by Init before it returns failure.
//
// This function may only be called from the main thread.
func Terminate() {
	C.glfwTerminate()
}

// GetVersion retrieves the major, minor and revision numbers of the GLFW
// library. It is intended for when you are using GLFW as a shared library and
// want to ensure that you are using the minimum required version.
//
// This function may be called before Init.
func GetVersion() (major, minor, revision int) {
	var (
		maj C.int
		min C.int
		rev C.int
	)

	C.glfwGetVersion(&maj, &min, &rev)
	return int(maj), int(min), int(rev)
}

// GetVersionString returns a static string generated at compile-time according
// to which configuration macros were defined. This is intended for use when
// submitting bug reports, to allow developers to see which code paths are
// enabled in a binary.
//
// This function may be called before Init.
func GetVersionString() string {
	return C.GoString(C.glfwGetVersionString())
}
<commit_msg>Removed comment<commit_after>package glfw3

//#cgo windows LDFLAGS: -lglfw3dll -lopengl32 -lgdi32
//#cgo windows CFLAGS: -DGLFW_DLL
//#cgo linux LDFLAGS: -lglfw
//#cgo darwin LDFLAGS: -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo
//#cgo freebsd LDFLAGS: -lglfw3 -lGL -lXrandr -lXxf86vm -lXi
//#include <GLFW/glfw3.h>
import "C"

const (
	VersionMajor    = C.GLFW_VERSION_MAJOR    // This is incremented when the API is changed in non-compatible ways.
	VersionMinor    = C.GLFW_VERSION_MINOR    // This is incremented when features are added to the API but it remains backward-compatible.
	VersionRevision = C.GLFW_VERSION_REVISION // This is incremented when a bug fix release is made that does not contain any API changes.
)

// Init initializes the GLFW library. Before most GLFW functions can be used,
// GLFW must be initialized, and before a program terminates GLFW should be
// terminated in order to free any resources allocated during or after
// initialization.
//
// If this function fails, it calls Terminate before returning. If it succeeds,
// you should call Terminate before the program exits.
//
// Additional calls to this function after successful initialization but before
// termination will succeed but will do nothing.
//
// This function may take several seconds to complete on some systems, while on
// other systems it may take only a fraction of a second to complete.
//
// On Mac OS X, this function will change the current directory of the
// application to the Contents/Resources subdirectory of the application's
// bundle, if present.
//
// This function may only be called from the main thread.
func Init() error {
	if glfwbool(C.glfwInit()) {
		return nil
	}
	return <-lastError
}

// Terminate destroys all remaining windows, frees any allocated resources and
// sets the library to an uninitialized state. Once this is called, you must
// again call Init successfully before you will be able to use most GLFW
// functions.
//
// If GLFW has been successfully initialized, this function should be called
// before the program exits. If initialization fails, there is no need to call
// this function, as it is called by Init before it returns failure.
//
// This function may only be called from the main thread.
func Terminate() {
	C.glfwTerminate()
}

// GetVersion retrieves the major, minor and revision numbers of the GLFW
// library. It is intended for when you are using GLFW as a shared library and
// want to ensure that you are using the minimum required version.
//
// This function may be called before Init.
func GetVersion() (major, minor, revision int) {
	var (
		maj C.int
		min C.int
		rev C.int
	)

	C.glfwGetVersion(&maj, &min, &rev)
	return int(maj), int(min), int(rev)
}

// GetVersionString returns a static string generated at compile-time according
// to which configuration macros were defined. This is intended for use when
// submitting bug reports, to allow developers to see which code paths are
// enabled in a binary.
//
// This function may be called before Init.
func GetVersionString() string {
	return C.GoString(C.glfwGetVersionString())
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
)

var (
	VERSION     = "0.10.0"
	SPACES      = regexp.MustCompile("\\s+")
	INVALID_POS = errors.New("invalid position")

	OK              = 0
	MATCH_FOUND     = 100
	MATCH_NOT_FOUND = 101
)

type Pos struct {
	Start, End *int
}

func (p Pos) String() (result string) {
	if p.Start != nil {
		result = strconv.Itoa(*p.Start)
	}

	result += ":"

	if p.End != nil {
		result += strconv.Itoa(*p.End)
	}

	return
}

func (p *Pos) Set(s string) error {
	p.Start = nil
	p.End = nil

	parts := strings.Split(s, ":")
	if len(parts) < 1 || len(parts) > 2 {
		return INVALID_POS
	}

	if len(parts[0]) > 0 {
		v, err := strconv.Atoi(parts[0])
		if err != nil {
			return err
		}

		p.Start = &v
	}

	if len(parts) == 1 {
		// not a slice
		// note: same pointer (to distinguish from *p.End == *p.Start that returns an empty slice)
		p.End = p.Start
	} else if len(parts[1]) > 0 {
		v, err := strconv.Atoi(parts[1])
		if err != nil {
			return err
		}

		p.End = &v
	}

	return nil
}

func Slice(source []string, p Pos) []string {
	var start, end int

	if p.Start == nil {
		start = 0
	} else if *p.Start >= len(source) {
		return source[0:0]
	} else if *p.Start < 0 {
		start = len(source) + *p.Start

		if start < 0 {
			start = 0
		}
	} else {
		start = *p.Start
	}

	if p.End == p.Start {
		// this should return source[start]
		end = start + 1
	} else if p.End == nil || *p.End >= len(source) {
		return source[start:]
	} else if *p.End < 0 {
		end = len(source) + *p.End
	} else {
		end = *p.End
	}

	if end < start {
		end = start
	}

	return source[start:end]
}

func Quote(a []string) []string {
	q := make([]string, len(a))
	for i, s := range a {
		q[i] = fmt.Sprintf("%q", s)
	}

	return q
}

func Unquote(a []string) []string {
	q := make([]string, len(a))
	for i, s := range a {
		q[i] = strings.Trim(s, `"'`)
	}

	return q
}

func Print(format string, a []string) {
	printable := make([]interface{}, len(a))

	for i, v := range a {
		printable[i] = v
	}

	fmt.Printf(format, printable...)
}

func main() {
	version := flag.Bool("version", false, "print version and exit")
	quote := flag.Bool("quote", false, "quote returned fields")
	unquote := flag.Bool("unquote", false, "quote returned fields")
	ifs := flag.String("ifs", " ", "input field separator")
	ire := flag.String("ifs-re", "", "input field separator (as regular expression)")
	ofs := flag.String("ofs", " ", "input field separator")
	re := flag.String("re", "", "regular expression for parsing input")
	format := flag.String("printf", "", "output is formatted according to specified format")
	matches := flag.String("matches", "", "return status code 100 if any line matches the specified pattern, 101 otherwise")
	after := flag.String("after", "", "process line after specified tag")

	flag.Parse()

	if *version {
		fmt.Printf("%s version %s\n", path.Base(os.Args[0]), VERSION)
		return
	}

	pos := make([]Pos, len(flag.Args()))

	for i, arg := range flag.Args() {
		pos[i].Set(arg)
	}

	if len(*format) > 0 && !strings.HasSuffix(*format, "\n") {
		*format += "\n"
	}

	var split_re *regexp.Regexp
	var split_pattern *regexp.Regexp
	var match_pattern *regexp.Regexp
	status_code := OK

	if len(*matches) > 0 {
		match_pattern = regexp.MustCompile(*matches)
		status_code = MATCH_NOT_FOUND
	}

	if len(*re) > 0 {
		split_pattern = regexp.MustCompile(*re)
	}

	if len(*ire) > 0 {
		split_re = regexp.MustCompile(*ire)
	}

	scanner := bufio.NewScanner(os.Stdin)
	len_after := len(*after)

	for scanner.Scan() {
		if scanner.Err() != nil {
			log.Fatal(scanner.Err())
		}

		line := scanner.Text()

		if len_after > 0 {
			i := strings.Index(line, *after)
			if i < 0 {
				continue // no match
			}

			line = line[i+len_after:]
		}

		fields := []string{line} // $0 is the full line

		// split the line according to input field separator
		if split_pattern != nil {
			if matches := split_pattern.FindStringSubmatch(line); matches != nil {
				fields = matches
			}
		} else if split_re != nil {
			fields = append(fields, split_re.Split(line, -1)...)
		} else if *ifs == " " {
			fields = append(fields, SPACES.Split(strings.TrimSpace(line), -1)...)
		} else {
			fields = append(fields, strings.Split(line, *ifs)...)
		}

		var result []string

		// do some processing
		if len(pos) > 0 {
			result = make([]string, 0)

			for _, p := range pos {
				val := strings.Join(Slice(fields, p), *ifs)
				result = append(result, val)
			}
		} else {
			result = fields[0:1]
		}

		if *unquote {
			result = Unquote(result)
		}

		if *quote {
			result = Quote(result)
		}

		if len(*format) > 0 {
			Print(*format, result)
		} else {
			// join the result according to output field separator
			fmt.Println(strings.Join(result, *ofs))
		}

		if match_pattern != nil && match_pattern.MatchString(line) {
			status_code = MATCH_FOUND
		}
	}

	os.Exit(status_code)
}
<commit_msg>added --grep command, like --re but skips lines that don't match<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
)

var (
	VERSION     = "0.10.0"
	SPACES      = regexp.MustCompile("\\s+")
	INVALID_POS = errors.New("invalid position")

	OK              = 0
	MATCH_FOUND     = 100
	MATCH_NOT_FOUND = 101
)

type Pos struct {
	Start, End *int
}

func (p Pos) String() (result string) {
	if p.Start != nil {
		result = strconv.Itoa(*p.Start)
	}

	result += ":"

	if p.End != nil {
		result += strconv.Itoa(*p.End)
	}

	return
}

func (p *Pos) Set(s string) error {
	p.Start = nil
	p.End = nil

	parts := strings.Split(s, ":")
	if len(parts) < 1 || len(parts) > 2 {
		return INVALID_POS
	}

	if len(parts[0]) > 0 {
		v, err := strconv.Atoi(parts[0])
		if err != nil {
			return err
		}

		p.Start = &v
	}

	if len(parts) == 1 {
		// not a slice
		// note: same pointer (to distinguish from *p.End == *p.Start that returns an empty slice)
		p.End = p.Start
	} else if len(parts[1]) > 0 {
		v, err := strconv.Atoi(parts[1])
		if err != nil {
			return err
		}

		p.End = &v
	}

	return nil
}

func Slice(source []string, p Pos) []string {
	var start, end int

	if p.Start == nil {
		start = 0
	} else if *p.Start >= len(source) {
		return source[0:0]
	} else if *p.Start < 0 {
		start = len(source) + *p.Start

		if start < 0 {
			start = 0
		}
	} else {
		start = *p.Start
	}

	if p.End == p.Start {
		// this should return source[start]
		end = start + 1
	} else if p.End == nil || *p.End >= len(source) {
		return source[start:]
	} else if *p.End < 0 {
		end = len(source) + *p.End
	} else {
		end = *p.End
	}

	if end < start {
		end = start
	}

	return source[start:end]
}

func Quote(a []string) []string {
	q := make([]string, len(a))
	for i, s := range a {
		q[i] = fmt.Sprintf("%q", s)
	}

	return q
}

func Unquote(a []string) []string {
	q := make([]string, len(a))
	for i, s := range a {
		q[i] = strings.Trim(s, `"'`)
	}

	return q
}

func Print(format string, a []string) {
	printable := make([]interface{}, len(a))

	for i, v := range a {
		printable[i] = v
	}

	fmt.Printf(format, printable...)
}

func main() {
	version := flag.Bool("version", false, "print version and exit")
	quote := flag.Bool("quote", false, "quote returned fields")
	unquote := flag.Bool("unquote", false, "quote returned fields")
	ifs := flag.String("ifs", " ", "input field separator")
	ire := flag.String("ifs-re", "", "input field separator (as regular expression)")
	ofs := flag.String("ofs", " ", "input field separator")
	re := flag.String("re", "", "regular expression for parsing input")
	grep := flag.String("grep", "", "output only lines that match the regular expression")
	format := flag.String("printf", "", "output is formatted according to specified format")
	matches := flag.String("matches", "", "return status code 100 if any line matches the specified pattern, 101 otherwise")
	after := flag.String("after", "", "process line after specified tag")

	flag.Parse()

	if *version {
		fmt.Printf("%s version %s\n", path.Base(os.Args[0]), VERSION)
		return
	}

	pos := make([]Pos, len(flag.Args()))

	for i, arg := range flag.Args() {
		pos[i].Set(arg)
	}

	if len(*format) > 0 && !strings.HasSuffix(*format, "\n") {
		*format += "\n"
	}

	var split_re *regexp.Regexp
	var split_pattern *regexp.Regexp
	var match_pattern *regexp.Regexp
	var grep_pattern *regexp.Regexp
	status_code := OK

	if len(*matches) > 0 {
		match_pattern = regexp.MustCompile(*matches)
		status_code = MATCH_NOT_FOUND
	}

	if len(*grep) > 0 {
		grep_pattern = regexp.MustCompile(*grep)
	}

	if len(*re) > 0 {
		split_pattern = regexp.MustCompile(*re)
	}

	if len(*ire) > 0 {
		split_re = regexp.MustCompile(*ire)
	}

	scanner := bufio.NewScanner(os.Stdin)
	len_after := len(*after)

	for scanner.Scan() {
		if scanner.Err() != nil {
			log.Fatal(scanner.Err())
		}

		line := scanner.Text()

		if len_after > 0 {
			i := strings.Index(line, *after)
			if i < 0 {
				continue // no match
			}

			line = line[i+len_after:]
		}

		fields := []string{line} // $0 is the full line

		if grep_pattern != nil {
			if matches := grep_pattern.FindStringSubmatch(line); matches != nil {
				fields = matches
                        } else {
                                continue
                        }
		} else if split_pattern != nil {
			if matches := split_pattern.FindStringSubmatch(line); matches != nil {
				fields = matches
			}
		} else if split_re != nil {
                        // split line according to input regular expression
			fields = append(fields, split_re.Split(line, -1)...)
		} else if *ifs == " " {
                        // split line on spaces (compact multiple spaces)
			fields = append(fields, SPACES.Split(strings.TrimSpace(line), -1)...)
		} else {
		        // split line according to input field separator
			fields = append(fields, strings.Split(line, *ifs)...)
		}

		var result []string

		// do some processing
		if len(pos) > 0 {
			result = make([]string, 0)

			for _, p := range pos {
				val := strings.Join(Slice(fields, p), *ifs)
				result = append(result, val)
			}
		} else {
			result = fields[0:1]
		}

		if *unquote {
			result = Unquote(result)
		}

		if *quote {
			result = Quote(result)
		}

		if len(*format) > 0 {
			Print(*format, result)
		} else {
			// join the result according to output field separator
			fmt.Println(strings.Join(result, *ofs))
		}

		if match_pattern != nil && match_pattern.MatchString(line) {
			status_code = MATCH_FOUND
		}
	}

	os.Exit(status_code)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"strings"
)

const (
	GitIgnore = ".gitignore"
)

var (
	GOPATH = os.Getenv("GOPATH")

	dir = ""
)

func main() {
	log.SetFlags(0)

	if len(os.Args) < 2 {
		failAndUsage("Please specify a command")
	}
	cmd := strings.ToLower(os.Args[1])
	switch cmd {
	case "init":
		doinit()
	case "get":
		get()
	default:
		failAndUsage("Unknown command: %s", cmd)
	}
}

func doinit() {
	var err error
	dir, err = os.Getwd()
	if err != nil {
		log.Fatalf("Unable to determine current directory: %s", err)
	}

	if exists(".git") {
		log.Fatalf("%s already contains a .git folder, can't initialize gost", dir)
	}

	// Initialize a git repo
	run("git", "init")

	writeAndCommit(GitIgnore, DefaultGitIgnore, "Initialized repo with a .gitignore file")

	// Done
	log.Printf("Initialized git repo with a default README.md, please set your GOPATH to \"%s\", e.g.", dir)
	log.Printf("  export GOPATH=\"%s\"", dir)
	os.Setenv("GOPATH", dir)
}

func get() {
	requireGOPATH()

	flags := flag.NewFlagSet("get", flag.ExitOnError)
	update := flags.Bool("u", false, "update existing from remote")
	flags.Parse(os.Args[2:])
	args := flags.Args()
	if len(args) < 1 {
		log.Fatal("Please specify a package")
	}

	pkg := args[0]
	if !isGithub(pkg) {
		log.Fatal("gost only supports packages on github.com")
	}

	branch := "master"
	if len(args) > 1 {
		branch = args[1]
	}

	fetchSubtree(pkg, branch, *update, map[string]bool{})

	run("git", "add", "src")
	run("git", "commit", "-m", fmt.Sprintf("[gost] Added %s and its dependencies", pkg))
}

func fetchSubtree(pkg string, branch string, update bool, alreadyFetched map[string]bool) {
	// Take only the path up to the github repo
	pkgParts := strings.Split(pkg, "/")
	pkgRoot := path.Join(pkgParts[:3]...)
	if alreadyFetched[pkgRoot] {
		return
	}

	prefix := path.Join("src", pkgRoot)
	if exists(prefix) {
		if update {
			run("git", "subtree", "pull", "--squash",
				"--prefix", prefix,
				fmt.Sprintf("https://%s.git", pkgRoot),
				branch)
		} else {
			log.Printf("%s already exists, declining to add as subtree", prefix)
		}
	} else {
		run("git", "subtree", "add", "--squash",
			"--prefix", prefix,
			fmt.Sprintf("https://%s.git", pkgRoot),
			branch)
	}
	alreadyFetched[pkgRoot] = true
	fetchDeps(pkg, "master", update, alreadyFetched)
}

func fetchDeps(pkg string, branch string, update bool, alreadyFetched map[string]bool) {
	depsString := run("go", "list", "-f", "{{range .Deps}}{{.}} {{end}} {{range .TestImports}}{{.}} {{end}}", pkg)
	deps := parseDeps(depsString)

	nonGithubDeps := []string{}
	for _, dep := range deps {
		dep = strings.TrimSpace(dep)
		if dep == "" || dep == "." {
			continue
		}
		if isGithub(dep) {
			fetchSubtree(dep, branch, update, alreadyFetched)
		} else {
			nonGithubDeps = append(nonGithubDeps, dep)
		}
	}

	for _, dep := range nonGithubDeps {
		goGet(dep, update, alreadyFetched)
	}
}

func goGet(pkg string, update bool, alreadyFetched map[string]bool) {
	if alreadyFetched[pkg] {
		return
	}
	args := []string{"get"}
	if update {
		args = append(args, "-u")
	}
	args = append(args, pkg)
	run("go", args...)
	alreadyFetched[pkg] = true
}

func writeAndCommit(file string, content string, comment string) {
	if exists(file) {
		log.Fatalf("%s already contains %s, can't initialize gost", dir, file)
	}

	err := ioutil.WriteFile(file, []byte(content), 0644)
	if err != nil {
		log.Fatalf("Unable to write %s: %s", file, err)
	}

	// Write and commit
	run("git", "add", file)
	run("git", "commit", file, "-m", "[gost] "+comment)
}

func requireGOPATH() {
	if GOPATH == "" {
		log.Fatal("Please set your GOPATH")
	}
}

func exists(file string) bool {
	_, err := os.Stat(file)
	return err == nil
}

func isGithub(pkg string) bool {
	return strings.Index(pkg, "github.com/") == 0
}

func parseDeps(depsString string) []string {
	depsString = strings.Replace(depsString, "[", "", -1)
	depsString = strings.Replace(depsString, "]", "", -1)
	return strings.Split(depsString, " ")
}

func run(prg string, args ...string) string {
	out, err := doRun(prg, args...)
	if err != nil {
		log.Fatal(err)
	}
	return out
}

func doRun(prg string, args ...string) (string, error) {
	cmd := exec.Command(prg, args...)
	log.Printf("Running %s %s", prg, strings.Join(args, " "))
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%s says %s", prg, string(out))
	}
	return string(out), nil
}

func failAndUsage(msg string, args ...interface{}) {
	log.Printf(msg, args...)
	log.Fatal(`
Commands:
	init - initialize a git repo in the current directory and set GOPATH to here
	get  - like go get, except that all github dependencies are imported as subtrees
`)
}

const DefaultGitIgnore = `pkg
bin
.DS_Store
`
<commit_msg>Fix for gopkg.in<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
)

const (
	GitIgnore = ".gitignore"
)

var (
	GOPATH = os.Getenv("GOPATH")

	dir = ""
)

func main() {
	log.SetFlags(0)

	if len(os.Args) < 2 {
		failAndUsage("Please specify a command")
	}
	cmd := strings.ToLower(os.Args[1])
	switch cmd {
	case "init":
		doinit()
	case "get":
		get()
	default:
		failAndUsage("Unknown command: %s", cmd)
	}
}

func doinit() {
	var err error
	dir, err = os.Getwd()
	if err != nil {
		log.Fatalf("Unable to determine current directory: %s", err)
	}

	if exists(".git") {
		log.Fatalf("%s already contains a .git folder, can't initialize gost", dir)
	}

	// Initialize a git repo
	run("git", "init")

	writeAndCommit(GitIgnore, DefaultGitIgnore, "Initialized repo with a .gitignore file")

	// Done
	log.Printf("Initialized git repo with a default README.md, please set your GOPATH to \"%s\", e.g.", dir)
	log.Printf("  export GOPATH=\"%s\"", dir)
	os.Setenv("GOPATH", dir)
}

func get() {
	requireGOPATH()

	flags := flag.NewFlagSet("get", flag.ExitOnError)
	update := flags.Bool("u", false, "update existing from remote")
	flags.Parse(os.Args[2:])
	args := flags.Args()
	if len(args) < 1 {
		log.Fatal("Please specify a package")
	}

	pkg := args[0]
	if !isGithub(pkg) {
		log.Fatal("gost only supports packages on github.com")
	}

	branch := "master"
	if len(args) > 1 {
		branch = args[1]
	}

	fetchSubtree(pkg, branch, *update, map[string]bool{})
	removeGitFolders()

	run("git", "add", "src")
	run("git", "commit", "-m", fmt.Sprintf("[gost] Added %s and its dependencies", pkg))
}

func fetchSubtree(pkg string, branch string, update bool, alreadyFetched map[string]bool) {
	// Take only the path up to the github repo
	pkgParts := strings.Split(pkg, "/")
	pkgRoot := path.Join(pkgParts[:3]...)
	if alreadyFetched[pkgRoot] {
		return
	}

	prefix := path.Join("src", pkgRoot)
	if exists(prefix) {
		if update {
			run("git", "subtree", "pull", "--squash",
				"--prefix", prefix,
				fmt.Sprintf("https://%s.git", pkgRoot),
				branch)
		} else {
			log.Printf("%s already exists, declining to add as subtree", prefix)
		}
	} else {
		run("git", "subtree", "add", "--squash",
			"--prefix", prefix,
			fmt.Sprintf("https://%s.git", pkgRoot),
			branch)
	}
	alreadyFetched[pkgRoot] = true
	fetchDeps(pkg, "master", update, alreadyFetched)
}

func fetchDeps(pkg string, branch string, update bool, alreadyFetched map[string]bool) {
	depsString := run("go", "list", "-f", "{{range .Deps}}{{.}} {{end}} {{range .TestImports}}{{.}} {{end}}", pkg)
	deps := parseDeps(depsString)

	nonGithubDeps := []string{}
	for _, dep := range deps {
		dep = strings.TrimSpace(dep)
		if dep == "" || dep == "." {
			continue
		}
		if isGithub(dep) {
			fetchSubtree(dep, branch, update, alreadyFetched)
		} else {
			nonGithubDeps = append(nonGithubDeps, dep)
		}
	}

	for _, dep := range nonGithubDeps {
		goGet(dep, update, alreadyFetched)
	}
}

func goGet(pkg string, update bool, alreadyFetched map[string]bool) {
	if alreadyFetched[pkg] {
		return
	}
	args := []string{"get"}
	if update {
		args = append(args, "-u")
	}
	args = append(args, pkg)
	run("go", args...)
	alreadyFetched[pkg] = true
}

func writeAndCommit(file string, content string, comment string) {
	if exists(file) {
		log.Fatalf("%s already contains %s, can't initialize gost", dir, file)
	}

	err := ioutil.WriteFile(file, []byte(content), 0644)
	if err != nil {
		log.Fatalf("Unable to write %s: %s", file, err)
	}

	// Write and commit
	run("git", "add", file)
	run("git", "commit", file, "-m", "[gost] "+comment)
}

func requireGOPATH() {
	if GOPATH == "" {
		log.Fatal("Please set your GOPATH")
	}
}

func exists(file string) bool {
	_, err := os.Stat(file)
	return err == nil
}

func isGithub(pkg string) bool {
	return strings.Index(pkg, "github.com/") == 0
}

func parseDeps(depsString string) []string {
	depsString = strings.Replace(depsString, "[", "", -1)
	depsString = strings.Replace(depsString, "]", "", -1)
	return strings.Split(depsString, " ")
}

// removeGitFolders removes all .git folders under the src tree so that any git
// repos that didn't come from GitHub (e.g. gopkg.in) won't be treated as
// submodules.
func removeGitFolders() {
	filepath.Walk(path.Join(GOPATH, "src"), func(dir string, info os.FileInfo, oldErr error) error {
		_, file := path.Split(dir)
		if file == ".git" {
			log.Printf("Removing git folder at %s", dir)
			err := os.RemoveAll(dir)
			if err != nil {
				log.Printf("WARNING - unable to remove git folder at %s", err)
			}
		}
		return nil
	})
}

func run(prg string, args ...string) string {
	out, err := doRun(prg, args...)
	if err != nil {
		log.Fatal(err)
	}
	return out
}

func doRun(prg string, args ...string) (string, error) {
	cmd := exec.Command(prg, args...)
	log.Printf("Running %s %s", prg, strings.Join(args, " "))
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("%s says %s", prg, string(out))
	}
	return string(out), nil
}

func failAndUsage(msg string, args ...interface{}) {
	log.Printf(msg, args...)
	log.Fatal(`
Commands:
	init - initialize a git repo in the current directory and set GOPATH to here
	get  - like go get, except that all github dependencies are imported as subtrees
`)
}

const DefaultGitIgnore = `pkg
bin
.DS_Store
`
<|endoftext|>


<commit_before>// 31 august 2014

package ui

import (
	"fmt"
)

// Grid is a Control that arranges other Controls in a grid.
// Grid is a very powerful container: it can position and size each Control in several ways and can (and must) have Controls added to it at any time, in any direction.
// [TODO it can also have Controls spanning multiple rows and columns.]
//
// Each Control in a Grid has associated "expansion" and "alignment" values in both the X and Y direction.
// Expansion determines whether all cells in the same row/column are given whatever space is left over after figuring out how big the rest of the Grid should be.
// Alignment determines the position of a Control relative to its cell after computing the above.
// The special alignment Fill can be used to grow a Control to fit its cell.
// Note that expansion and alignment are independent variables.
// For more information on expansion and alignment, read https://developer.gnome.org/gtk3/unstable/ch28s02.html.
type Grid interface {
	Control

	// Add adds a Control to the Grid.
	// If this is the first Control in the Grid, it is merely added; nextTo should be nil.
	// Otherwise, it is placed relative to nextTo.
	// If nextTo is nil, it is placed next to the previously added Control.
	// The effect of adding the same Control multiple times is undefined, as is the effect of adding a Control next to one not present in the Grid.
	Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align)
}

// Align represents the alignment of a Control in its cell of a Grid.
type Align uint
const (
	LeftTop Align = iota
	Center
	RightBottom
	Fill
)

// Side represents a side of a Control to add other Controls to a Grid to.
type Side uint
const (
	// this arrangement is important
	// it makes finding the opposite side as easy as ^ 1
	West Side = iota
	East
	North
	South
	nSides
)

type grid struct {
	controls		map[Control]*gridCell
	prev			Control
	parent		*controlParent

	// for allocate() and preferredSize()
	xoff, yoff		int
	xmax, ymax	int
	grid			[][]Control
}

type gridCell struct {
	xexpand		bool
	xalign		Align
	yexpand		bool
	yalign		Align
	neighbors		[nSides]Control

	// for allocate() and preferredSize()
	gridx		int
	gridy		int
	xoff			int
	yoff			int
	width		int
	height		int
	visited		bool
}

// NewGrid creates a new Grid with no Controls.
func NewGrid() Grid {
	return &grid{
		controls:		map[Control]*gridCell{},
	}
}

func (g *grid) Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align) {
	cell := &gridCell{
		xexpand:		xexpand,
		xalign:		xalign,
		yexpand:		yexpand,
		yalign:		yalign,
	}
	// if this is the first control, just add it in directly
	if len(g.controls) != 0 {
		if nextTo == nil {
			nextTo = g.prev
		}
		next := g.controls[nextTo]
		// squeeze any control previously on the same side out of the way
		temp := next.neighbors[side]
		next.neighbors[side] = control
		cell.neighbors[side] = temp
		cell.neighbors[side ^ 1] = nextTo		// doubly-link
	}
	g.controls[control] = cell
	g.prev = control
	if g.parent != nil {
		control.setParent(g.parent)
	}
}

func (g *grid) setParent(p *controlParent) {
	g.parent = p
	for c, _ := range g.controls {
		c.setParent(g.parent)
	}
}

func (g *grid) trasverse(c Control, x int, y int) {
	cell := g.controls[c]
	if cell.visited {
		return
	}
	cell.visited = true
	cell.gridx = x
	cell.gridy = y
	if x < g.xoff {
		g.xoff = x
	}
	if y < g.yoff {
		g.yoff = y
	}
	if cell.neighbors[West] != nil {
		g.trasverse(cell.neighbors[West], x - 1, y)
	}
	if cell.neighbors[North] != nil {
		g.trasverse(cell.neighbors[North], x, y - 1)
	}
	if cell.neighbors[East] != nil {
		g.trasverse(cell.neighbors[East], x + 1, y)
	}
	if cell.neighbors[South] != nil {
		g.trasverse(cell.neighbors[South], x, y + 1)
	}
}

func (g *grid) buildGrid() {
	// thanks to http://programmers.stackexchange.com/a/254968/147812
	// before we do anything, reset the visited bits
	for _, cell := range g.controls {
		cell.visited = false
	}
	// we first mark the previous control as the origin...
	g.xoff = 0
	g.yoff = 0
	g.trasverse(g.prev, 0, 0)		// start at the last control added
	// now we need to make all offsets zero-based
	g.xoff = -g.xoff
	g.yoff = -g.yoff
	g.xmax = 0
	g.ymax = 0
	for _, cell := range g.controls {
		cell.gridx += g.xoff
		cell.gridy += g.yoff
		if cell.gridx > g.xmax {
			g.xmax = cell.gridx
		}
		if cell.gridy > g.ymax {
			g.ymax = cell.gridy
		}
	}
	// g.xmax and g.ymax are the last valid index; make them one over to make everything work
	g.xmax++
	g.ymax++
	// and finally build the matrix
	g.grid = make([][]Control, g.ymax)
	for y := 0; y < g.ymax; y++ {
		g.grid[y] = make([]Control, g.xmax)
		// the elements are assigned below for efficiency
	}
}

func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
	if len(g.controls) == 0 {
		// nothing to do
		return nil
	}

	// 1) compute the resultant grid
	g.buildGrid()
	width -= d.xpadding * g.xmax
	height -= d.ypadding * g.ymax

	// 2) for every control, set the width of each cell of its column/height of each cell of its row to the largest such
	colwidths := make([]int, g.xmax)
	rowheights := make([]int, g.ymax)
	colxexpand := make([]bool, g.xmax)
	rowyexpand := make([]bool, g.ymax)
	for c, cell := range g.controls {
		width, height := c.preferredSize(d)
		cell.width = width
		cell.height = height
		if colwidths[cell.gridx] < width {
			colwidths[cell.gridx] = width
		}
		if rowheights[cell.gridy] < height {
			rowheights[cell.gridy] = height
		}
		if cell.xexpand {
			colxexpand[cell.gridx] = true
		}
		if cell.yexpand {
			rowyexpand[cell.gridy] = true
		}
		g.grid[cell.gridy][cell.gridx] = c
	}

	// 3) distribute the remaining space equally to expanding cells, adjusting widths and heights as needed
	nexpand := 0
	for x, expand := range colxexpand {
		if expand {
			nexpand++
		} else {		// column width known; subtract it
			width -= colwidths[x]
		}
	}
	if nexpand > 0 {
		w := width / nexpand
		for x, expand := range colxexpand {
			if expand {
				colwidths[x] = w
			}
		}
	}
	nexpand = 0
	for y, expand := range rowyexpand {
		if expand {
			nexpand++
		} else {		// row height known; subtract it
			height -= rowheights[y]
		}
	}
	if nexpand > 0 {
		h := height / nexpand
		for y, expand := range rowyexpand {
			if expand {
				rowheights[y] = h
			}
		}
	}

	// all right, now we have the size of each cell

	// 4) handle alignment
	for _, cell := range g.controls {
		cell.xoff = 0
		switch cell.xalign {
		case LeftTop:
			// do nothing; this is the default
		case Center:
			cell.xoff = (colwidths[cell.gridx] - cell.width) / 2
		case RightBottom:
			cell.xoff = colwidths[cell.gridx] - cell.width
		case Fill:
			cell.width = colwidths[cell.gridx]
		default:
			panic(fmt.Errorf("invalid xalign %d in Grid.allocate()", cell.xalign))
		}
		cell.yoff = 0
		switch cell.yalign {
		case LeftTop:
			// do nothing; this is the default
		case Center:
			cell.yoff = (rowheights[cell.gridy] - cell.height) / 2
		case RightBottom:
			cell.yoff = rowheights[cell.gridy] - cell.height
		case Fill:
			cell.height = rowheights[cell.gridy]
		default:
			panic(fmt.Errorf("invalid yalign %d in Grid.allocate()", cell.yalign))
		}
	}

	// 5) draw
	var current *allocation

	startx := x
	for row, xcol := range g.grid {
		current = nil
		for col, c := range xcol {
			cell := g.controls[c]
			as := c.allocate(x + cell.xoff, y + cell.yoff, cell.width, cell.height, d)
			if current != nil {			// connect first left to first right
				current.neighbor = c
			}
			if len(as) != 0 {
				current = as[0]			// next left is first subwidget
			} else {
				current = nil			// spaces don't have allocation data
			}
			allocations = append(allocations, as...)
			x += colwidths[col] + d.xpadding
		}
		x = startx
		y += rowheights[row] + d.ypadding
	}

	return allocations
}

func (g *grid) preferredSize(d *sizing) (width, height int) {
	if len(g.controls) == 0 {
		// nothing to do
		return 0, 0
	}

	// 1) compute the resultant grid
	g.buildGrid()

	// 2) for every control (including those that don't expand), set the width of each cell of its column/height of each cell of its row to the largest such
	colwidths := make([]int, g.xmax)
	rowheights := make([]int, g.ymax)
	for c, cell := range g.controls {
		width, height := c.preferredSize(d)
		cell.width = width
		cell.height = height
		if colwidths[cell.gridx] < width {
			colwidths[cell.gridx] = width
		}
		if rowheights[cell.gridy] < height {
			rowheights[cell.gridy] = height
		}
	}

	// 3) and sum the widths and heights
	maxx := 0
	for _, x := range colwidths {
		maxx += x
	}
	maxy := 0
	for _, y := range rowheights {
		maxy += y
	}

	// and that's it really; just discount the padding
	return maxx + (g.xmax - 1) * d.xpadding,
		maxy + (g.ymax - 1) * d.ypadding
}

func (g *grid) commitResize(a *allocation, d *sizing) {
	// do nothing; needed to satisfy Control
}

func (g *grid) getAuxResizeInfo(d *sizing) {
	// do nothing; needed to satisfy Control
}
<commit_msg>Fixed empty cells in Grid not handled correctly.<commit_after>// 31 august 2014

package ui

import (
	"fmt"
)

// Grid is a Control that arranges other Controls in a grid.
// Grid is a very powerful container: it can position and size each Control in several ways and can (and must) have Controls added to it at any time, in any direction.
// [TODO it can also have Controls spanning multiple rows and columns.]
//
// Each Control in a Grid has associated "expansion" and "alignment" values in both the X and Y direction.
// Expansion determines whether all cells in the same row/column are given whatever space is left over after figuring out how big the rest of the Grid should be.
// Alignment determines the position of a Control relative to its cell after computing the above.
// The special alignment Fill can be used to grow a Control to fit its cell.
// Note that expansion and alignment are independent variables.
// For more information on expansion and alignment, read https://developer.gnome.org/gtk3/unstable/ch28s02.html.
type Grid interface {
	Control

	// Add adds a Control to the Grid.
	// If this is the first Control in the Grid, it is merely added; nextTo should be nil.
	// Otherwise, it is placed relative to nextTo.
	// If nextTo is nil, it is placed next to the previously added Control.
	// The effect of adding the same Control multiple times is undefined, as is the effect of adding a Control next to one not present in the Grid.
	Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align)
}

// Align represents the alignment of a Control in its cell of a Grid.
type Align uint
const (
	LeftTop Align = iota
	Center
	RightBottom
	Fill
)

// Side represents a side of a Control to add other Controls to a Grid to.
type Side uint
const (
	// this arrangement is important
	// it makes finding the opposite side as easy as ^ 1
	West Side = iota
	East
	North
	South
	nSides
)

type grid struct {
	controls		map[Control]*gridCell
	prev			Control
	parent		*controlParent

	// for allocate() and preferredSize()
	xoff, yoff		int
	xmax, ymax	int
	grid			[][]Control
}

type gridCell struct {
	xexpand		bool
	xalign		Align
	yexpand		bool
	yalign		Align
	neighbors		[nSides]Control

	// for allocate() and preferredSize()
	gridx		int
	gridy		int
	xoff			int
	yoff			int
	width		int
	height		int
	visited		bool
}

// NewGrid creates a new Grid with no Controls.
func NewGrid() Grid {
	return &grid{
		controls:		map[Control]*gridCell{},
	}
}

func (g *grid) Add(control Control, nextTo Control, side Side, xexpand bool, xalign Align, yexpand bool, yalign Align) {
	cell := &gridCell{
		xexpand:		xexpand,
		xalign:		xalign,
		yexpand:		yexpand,
		yalign:		yalign,
	}
	// if this is the first control, just add it in directly
	if len(g.controls) != 0 {
		if nextTo == nil {
			nextTo = g.prev
		}
		next := g.controls[nextTo]
		// squeeze any control previously on the same side out of the way
		temp := next.neighbors[side]
		next.neighbors[side] = control
		cell.neighbors[side] = temp
		cell.neighbors[side ^ 1] = nextTo		// doubly-link
	}
	g.controls[control] = cell
	g.prev = control
	if g.parent != nil {
		control.setParent(g.parent)
	}
}

func (g *grid) setParent(p *controlParent) {
	g.parent = p
	for c, _ := range g.controls {
		c.setParent(g.parent)
	}
}

func (g *grid) trasverse(c Control, x int, y int) {
	cell := g.controls[c]
	if cell.visited {
		return
	}
	cell.visited = true
	cell.gridx = x
	cell.gridy = y
	if x < g.xoff {
		g.xoff = x
	}
	if y < g.yoff {
		g.yoff = y
	}
	if cell.neighbors[West] != nil {
		g.trasverse(cell.neighbors[West], x - 1, y)
	}
	if cell.neighbors[North] != nil {
		g.trasverse(cell.neighbors[North], x, y - 1)
	}
	if cell.neighbors[East] != nil {
		g.trasverse(cell.neighbors[East], x + 1, y)
	}
	if cell.neighbors[South] != nil {
		g.trasverse(cell.neighbors[South], x, y + 1)
	}
}

func (g *grid) buildGrid() {
	// thanks to http://programmers.stackexchange.com/a/254968/147812
	// before we do anything, reset the visited bits
	for _, cell := range g.controls {
		cell.visited = false
	}
	// we first mark the previous control as the origin...
	g.xoff = 0
	g.yoff = 0
	g.trasverse(g.prev, 0, 0)		// start at the last control added
	// now we need to make all offsets zero-based
	g.xoff = -g.xoff
	g.yoff = -g.yoff
	g.xmax = 0
	g.ymax = 0
	for _, cell := range g.controls {
		cell.gridx += g.xoff
		cell.gridy += g.yoff
		if cell.gridx > g.xmax {
			g.xmax = cell.gridx
		}
		if cell.gridy > g.ymax {
			g.ymax = cell.gridy
		}
	}
	// g.xmax and g.ymax are the last valid index; make them one over to make everything work
	g.xmax++
	g.ymax++
	// and finally build the matrix
	g.grid = make([][]Control, g.ymax)
	for y := 0; y < g.ymax; y++ {
		g.grid[y] = make([]Control, g.xmax)
		// the elements are assigned below for efficiency
	}
}

func (g *grid) allocate(x int, y int, width int, height int, d *sizing) (allocations []*allocation) {
	if len(g.controls) == 0 {
		// nothing to do
		return nil
	}

	// 1) compute the resultant grid
	g.buildGrid()
	width -= d.xpadding * g.xmax
	height -= d.ypadding * g.ymax

	// 2) for every control, set the width of each cell of its column/height of each cell of its row to the largest such
	colwidths := make([]int, g.xmax)
	rowheights := make([]int, g.ymax)
	colxexpand := make([]bool, g.xmax)
	rowyexpand := make([]bool, g.ymax)
	for c, cell := range g.controls {
		width, height := c.preferredSize(d)
		cell.width = width
		cell.height = height
		if colwidths[cell.gridx] < width {
			colwidths[cell.gridx] = width
		}
		if rowheights[cell.gridy] < height {
			rowheights[cell.gridy] = height
		}
		if cell.xexpand {
			colxexpand[cell.gridx] = true
		}
		if cell.yexpand {
			rowyexpand[cell.gridy] = true
		}
		g.grid[cell.gridy][cell.gridx] = c
	}

	// 3) distribute the remaining space equally to expanding cells, adjusting widths and heights as needed
	nexpand := 0
	for x, expand := range colxexpand {
		if expand {
			nexpand++
		} else {		// column width known; subtract it
			width -= colwidths[x]
		}
	}
	if nexpand > 0 {
		w := width / nexpand
		for x, expand := range colxexpand {
			if expand {
				colwidths[x] = w
			}
		}
	}
	nexpand = 0
	for y, expand := range rowyexpand {
		if expand {
			nexpand++
		} else {		// row height known; subtract it
			height -= rowheights[y]
		}
	}
	if nexpand > 0 {
		h := height / nexpand
		for y, expand := range rowyexpand {
			if expand {
				rowheights[y] = h
			}
		}
	}

	// all right, now we have the size of each cell

	// 4) handle alignment
	for _, cell := range g.controls {
		cell.xoff = 0
		switch cell.xalign {
		case LeftTop:
			// do nothing; this is the default
		case Center:
			cell.xoff = (colwidths[cell.gridx] - cell.width) / 2
		case RightBottom:
			cell.xoff = colwidths[cell.gridx] - cell.width
		case Fill:
			cell.width = colwidths[cell.gridx]
		default:
			panic(fmt.Errorf("invalid xalign %d in Grid.allocate()", cell.xalign))
		}
		cell.yoff = 0
		switch cell.yalign {
		case LeftTop:
			// do nothing; this is the default
		case Center:
			cell.yoff = (rowheights[cell.gridy] - cell.height) / 2
		case RightBottom:
			cell.yoff = rowheights[cell.gridy] - cell.height
		case Fill:
			cell.height = rowheights[cell.gridy]
		default:
			panic(fmt.Errorf("invalid yalign %d in Grid.allocate()", cell.yalign))
		}
	}

	// 5) draw
	var current *allocation

	startx := x
	for row, xcol := range g.grid {
		current = nil
		for col, c := range xcol {
			if c != nil {					// treat empty cells like spaces
				cell := g.controls[c]
				as := c.allocate(x + cell.xoff, y + cell.yoff, cell.width, cell.height, d)
				if current != nil {		// connect first left to first right
					current.neighbor = c
				}
				if len(as) != 0 {
					current = as[0]		// next left is first subwidget
				} else {
					current = nil		// spaces don't have allocation data
				}
				allocations = append(allocations, as...)
			}
			x += colwidths[col] + d.xpadding
		}
		x = startx
		y += rowheights[row] + d.ypadding
	}

	return allocations
}

func (g *grid) preferredSize(d *sizing) (width, height int) {
	if len(g.controls) == 0 {
		// nothing to do
		return 0, 0
	}

	// 1) compute the resultant grid
	g.buildGrid()

	// 2) for every control (including those that don't expand), set the width of each cell of its column/height of each cell of its row to the largest such
	colwidths := make([]int, g.xmax)
	rowheights := make([]int, g.ymax)
	for c, cell := range g.controls {
		width, height := c.preferredSize(d)
		cell.width = width
		cell.height = height
		if colwidths[cell.gridx] < width {
			colwidths[cell.gridx] = width
		}
		if rowheights[cell.gridy] < height {
			rowheights[cell.gridy] = height
		}
	}

	// 3) and sum the widths and heights
	maxx := 0
	for _, x := range colwidths {
		maxx += x
	}
	maxy := 0
	for _, y := range rowheights {
		maxy += y
	}

	// and that's it really; just discount the padding
	return maxx + (g.xmax - 1) * d.xpadding,
		maxy + (g.ymax - 1) * d.ypadding
}

func (g *grid) commitResize(a *allocation, d *sizing) {
	// do nothing; needed to satisfy Control
}

func (g *grid) getAuxResizeInfo(d *sizing) {
	// do nothing; needed to satisfy Control
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"regexp"
	"path/filepath"
	"io/ioutil"
	"net/http"
	"errors"
)

type User struct {
	Name string
	Dir string
}

func GetUsers(installationDir string) []User {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		panic(err)
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId, "config")
		configFile := filepath.Join(userDir, "localconfig.vdf")

		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			panic(err)
		}
		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users
}

const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`
func GetProfile(username string) string {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		panic(err)
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		panic(err)
	}

	return string(contentBytes)
}

type Game struct {
	Id string
	Name string
}

const gamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`
func GetGames(username string) []Game {
	pattern := regexp.MustCompile(gamePattern)

	games := make([]Game, 0)

	profile := GetProfile(username)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		games = append(games, Game{groups[1], groups[2]})
	}

	return games
}

const imageUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/STORE_APP_ID_HERE/header.jpg`
func DownloadImage(gameid string, filename string) error {
	response, err := http.Get(imageUrlFormat)
	if err != nil {
		return err
	}

	var imageBytes []byte
	imageBytes, err = ioutil.ReadAll(response.Body)
	response.Body.Close()
	return ioutil.WriteFile(filename, imageBytes, 0666)
}

func containsSteam(path string) bool {
	_, err := os.Stat(filepath.Join(path, "Steam"))
	return err != nil
}
func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		if _, err = os.Stat(argDir); err == nil {
			return argDir, nil
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

func main() {
	installationDir, err := GetSteamInstallation()
	if err != nil {
		panic(err)
	}

	for _, user := range GetUsers(installationDir) {
		fmt.Printf("Found user %v. Fetching game list...\n", user.Name)
		continue

		games := GetGames(user.Name)
		fmt.Printf("Found %v games. Download images...\n", len(games))
		for _, game := range games {
			gridDir := filepath.Join(user.Dir, "grid")
			err := DownloadImage(game.Id, gridDir)
			fmt.Println(game.Id, game.Name)
			if err != nil {
				panic(err)
			}
		}
	}
}
<commit_msg>Error out when parameter is invalid<commit_after>package main

import (
	"fmt"
	"os"
	"regexp"
	"path/filepath"
	"io/ioutil"
	"net/http"
	"errors"
)

type User struct {
	Name string
	Dir string
}

func GetUsers(installationDir string) []User {
	userdataDir := filepath.Join(installationDir, "userdata")
	files, err := ioutil.ReadDir(userdataDir)
	if err != nil {
		panic(err)
	}

	users := make([]User, 0)

	for _, userDir := range files {
		userId := userDir.Name()
		userDir := filepath.Join(userdataDir, userId, "config")
		configFile := filepath.Join(userDir, "localconfig.vdf")

		configBytes, err := ioutil.ReadFile(configFile)
		if err != nil {
			panic(err)
		}
		pattern := regexp.MustCompile(`"PersonaName"\s*"(.+?)"`)
		username := pattern.FindStringSubmatch(string(configBytes))[1]
		users = append(users, User{username, userDir})
	}

	return users
}

const urlFormat = `http://steamcommunity.com/id/%v/games?tab=all`
func GetProfile(username string) string {
	response, err := http.Get(fmt.Sprintf(urlFormat, username))
	if err != nil {
		panic(err)
	}

	contentBytes, err := ioutil.ReadAll(response.Body)
	response.Body.Close()
	if err != nil {
		panic(err)
	}

	return string(contentBytes)
}

type Game struct {
	Id string
	Name string
}

const gamePattern = `\{"appid":\s*(\d+),\s*"name":\s*"(.+?)"`
func GetGames(username string) []Game {
	pattern := regexp.MustCompile(gamePattern)

	games := make([]Game, 0)

	profile := GetProfile(username)
	for _, groups := range pattern.FindAllStringSubmatch(profile, -1) {
		games = append(games, Game{groups[1], groups[2]})
	}

	return games
}

const imageUrlFormat = `http://cdn.steampowered.com/v/gfx/apps/STORE_APP_ID_HERE/header.jpg`
func DownloadImage(gameid string, filename string) error {
	response, err := http.Get(imageUrlFormat)
	if err != nil {
		return err
	}

	var imageBytes []byte
	imageBytes, err = ioutil.ReadAll(response.Body)
	response.Body.Close()
	return ioutil.WriteFile(filename, imageBytes, 0666)
}

func containsSteam(path string) bool {
	_, err := os.Stat(filepath.Join(path, "Steam"))
	return err != nil
}
func GetSteamInstallation() (path string, err error) {
	if len(os.Args) == 2 {
		argDir := os.Args[1]
		_, err := os.Stat(argDir)
		if err == nil {
			return argDir, nil
		} else {
			return "", errors.New("Argument must be a valid Steam directory, or empty for auto detection. Got: " + argDir)
		}
	}

	programFiles86Dir := filepath.Join(os.Getenv("ProgramFiles(x86)"), "Steam")
	if _, err = os.Stat(programFiles86Dir); err == nil {
		return programFiles86Dir, nil
	}

	programFilesDir := filepath.Join(os.Getenv("ProgramFiles"), "Steam")
	if _, err = os.Stat(programFilesDir); err == nil {
		return programFilesDir, nil
	}

	return "", errors.New("Could not find Steam installation folder.")
}

func main() {
	installationDir, err := GetSteamInstallation()
	if err != nil {
		panic(err)
	}

	for _, user := range GetUsers(installationDir) {
		fmt.Printf("Found user %v. Fetching game list...\n", user.Name)
		continue

		games := GetGames(user.Name)
		fmt.Printf("Found %v games. Download images...\n", len(games))
		for _, game := range games {
			gridDir := filepath.Join(user.Dir, "grid")
			err := DownloadImage(game.Id, gridDir)
			fmt.Println(game.Id, game.Name)
			if err != nil {
				panic(err)
			}
		}
	}
}
<|endoftext|>


<commit_before>package operations

import (
	"context"
	"fmt"
	"testing"

	"github.com/rclone/rclone/fs/accounting"
	"github.com/rclone/rclone/fstest/mockfs"
	"github.com/rclone/rclone/fstest/mockobject"
	"github.com/rclone/rclone/lib/random"

	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fstest"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestDoMultiThreadCopy(t *testing.T) {
	f := mockfs.NewFs("potato", "")
	src := mockobject.New("file.txt").WithContent([]byte(random.String(100)), mockobject.SeekModeNone)
	srcFs := mockfs.NewFs("sausage", "")
	src.SetFs(srcFs)

	oldStreams := fs.Config.MultiThreadStreams
	oldCutoff := fs.Config.MultiThreadCutoff
	oldIsSet := fs.Config.MultiThreadSet
	defer func() {
		fs.Config.MultiThreadStreams = oldStreams
		fs.Config.MultiThreadCutoff = oldCutoff
		fs.Config.MultiThreadSet = oldIsSet
	}()

	fs.Config.MultiThreadStreams, fs.Config.MultiThreadCutoff = 4, 50
	fs.Config.MultiThreadSet = false

	nullWriterAt := func(ctx context.Context, remote string, size int64) (fs.WriterAtCloser, error) {
		panic("don't call me")
	}
	f.Features().OpenWriterAt = nullWriterAt

	assert.True(t, doMultiThreadCopy(f, src))

	fs.Config.MultiThreadStreams = 0
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadStreams = 1
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadStreams = 2
	assert.True(t, doMultiThreadCopy(f, src))

	fs.Config.MultiThreadCutoff = 200
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadCutoff = 101
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadCutoff = 100
	assert.True(t, doMultiThreadCopy(f, src))

	f.Features().OpenWriterAt = nil
	assert.False(t, doMultiThreadCopy(f, src))
	f.Features().OpenWriterAt = nullWriterAt
	assert.True(t, doMultiThreadCopy(f, src))

	f.Features().IsLocal = true
	srcFs.Features().IsLocal = true
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadSet = true
	assert.True(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadSet = false
	assert.False(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = true
	assert.False(t, doMultiThreadCopy(f, src))
	f.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
}

func TestMultithreadCalculateChunks(t *testing.T) {
	for _, test := range []struct {
		size         int64
		streams      int
		wantPartSize int64
		wantStreams  int
	}{
		{size: 1, streams: 10, wantPartSize: multithreadChunkSize, wantStreams: 1},
		{size: 1 << 20, streams: 1, wantPartSize: 1 << 20, wantStreams: 1},
		{size: 1 << 20, streams: 2, wantPartSize: 1 << 19, wantStreams: 2},
		{size: (1 << 20) + 1, streams: 2, wantPartSize: (1 << 19) + multithreadChunkSize, wantStreams: 2},
		{size: (1 << 20) - 1, streams: 2, wantPartSize: (1 << 19), wantStreams: 2},
	} {
		t.Run(fmt.Sprintf("%+v", test), func(t *testing.T) {
			mc := &multiThreadCopyState{
				size:    test.size,
				streams: test.streams,
			}
			mc.calculateChunks()
			assert.Equal(t, test.wantPartSize, mc.partSize)
			assert.Equal(t, test.wantStreams, mc.streams)
		})
	}
}

func TestMultithreadCopy(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()

	for _, test := range []struct {
		size    int
		streams int
	}{
		{size: multithreadChunkSize*2 - 1, streams: 2},
		{size: multithreadChunkSize * 2, streams: 2},
		{size: multithreadChunkSize*2 + 1, streams: 2},
	} {
		t.Run(fmt.Sprintf("%+v", test), func(t *testing.T) {
			if *fstest.SizeLimit > 0 && int64(test.size) > *fstest.SizeLimit {
				t.Skipf("exceeded file size limit %d > %d", test.size, *fstest.SizeLimit)
			}
			var err error
			contents := random.String(test.size)
			t1 := fstest.Time("2001-02-03T04:05:06.499999999Z")
			file1 := r.WriteObject(context.Background(), "file1", contents, t1)
			fstest.CheckItems(t, r.Fremote, file1)
			fstest.CheckItems(t, r.Flocal)

			src, err := r.Fremote.NewObject(context.Background(), "file1")
			require.NoError(t, err)
			accounting.GlobalStats().ResetCounters()
			tr := accounting.GlobalStats().NewTransfer(src)

			defer func() {
				tr.Done(err)
			}()
			dst, err := multiThreadCopy(context.Background(), r.Flocal, "file1", src, 2, tr)
			require.NoError(t, err)
			assert.Equal(t, src.Size(), dst.Size())
			assert.Equal(t, "file1", dst.Remote())

			fstest.CheckItems(t, r.Flocal, file1)
			require.NoError(t, dst.Remove(context.Background()))
		})
	}

}
<commit_msg>operations: fix multithread copy test to use the correct modify window<commit_after>package operations

import (
	"context"
	"fmt"
	"testing"

	"github.com/rclone/rclone/fs/accounting"
	"github.com/rclone/rclone/fstest/mockfs"
	"github.com/rclone/rclone/fstest/mockobject"
	"github.com/rclone/rclone/lib/random"

	"github.com/rclone/rclone/fs"
	"github.com/rclone/rclone/fstest"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestDoMultiThreadCopy(t *testing.T) {
	f := mockfs.NewFs("potato", "")
	src := mockobject.New("file.txt").WithContent([]byte(random.String(100)), mockobject.SeekModeNone)
	srcFs := mockfs.NewFs("sausage", "")
	src.SetFs(srcFs)

	oldStreams := fs.Config.MultiThreadStreams
	oldCutoff := fs.Config.MultiThreadCutoff
	oldIsSet := fs.Config.MultiThreadSet
	defer func() {
		fs.Config.MultiThreadStreams = oldStreams
		fs.Config.MultiThreadCutoff = oldCutoff
		fs.Config.MultiThreadSet = oldIsSet
	}()

	fs.Config.MultiThreadStreams, fs.Config.MultiThreadCutoff = 4, 50
	fs.Config.MultiThreadSet = false

	nullWriterAt := func(ctx context.Context, remote string, size int64) (fs.WriterAtCloser, error) {
		panic("don't call me")
	}
	f.Features().OpenWriterAt = nullWriterAt

	assert.True(t, doMultiThreadCopy(f, src))

	fs.Config.MultiThreadStreams = 0
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadStreams = 1
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadStreams = 2
	assert.True(t, doMultiThreadCopy(f, src))

	fs.Config.MultiThreadCutoff = 200
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadCutoff = 101
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadCutoff = 100
	assert.True(t, doMultiThreadCopy(f, src))

	f.Features().OpenWriterAt = nil
	assert.False(t, doMultiThreadCopy(f, src))
	f.Features().OpenWriterAt = nullWriterAt
	assert.True(t, doMultiThreadCopy(f, src))

	f.Features().IsLocal = true
	srcFs.Features().IsLocal = true
	assert.False(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadSet = true
	assert.True(t, doMultiThreadCopy(f, src))
	fs.Config.MultiThreadSet = false
	assert.False(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = true
	assert.False(t, doMultiThreadCopy(f, src))
	f.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
	srcFs.Features().IsLocal = false
	assert.True(t, doMultiThreadCopy(f, src))
}

func TestMultithreadCalculateChunks(t *testing.T) {
	for _, test := range []struct {
		size         int64
		streams      int
		wantPartSize int64
		wantStreams  int
	}{
		{size: 1, streams: 10, wantPartSize: multithreadChunkSize, wantStreams: 1},
		{size: 1 << 20, streams: 1, wantPartSize: 1 << 20, wantStreams: 1},
		{size: 1 << 20, streams: 2, wantPartSize: 1 << 19, wantStreams: 2},
		{size: (1 << 20) + 1, streams: 2, wantPartSize: (1 << 19) + multithreadChunkSize, wantStreams: 2},
		{size: (1 << 20) - 1, streams: 2, wantPartSize: (1 << 19), wantStreams: 2},
	} {
		t.Run(fmt.Sprintf("%+v", test), func(t *testing.T) {
			mc := &multiThreadCopyState{
				size:    test.size,
				streams: test.streams,
			}
			mc.calculateChunks()
			assert.Equal(t, test.wantPartSize, mc.partSize)
			assert.Equal(t, test.wantStreams, mc.streams)
		})
	}
}

func TestMultithreadCopy(t *testing.T) {
	r := fstest.NewRun(t)
	defer r.Finalise()

	for _, test := range []struct {
		size    int
		streams int
	}{
		{size: multithreadChunkSize*2 - 1, streams: 2},
		{size: multithreadChunkSize * 2, streams: 2},
		{size: multithreadChunkSize*2 + 1, streams: 2},
	} {
		t.Run(fmt.Sprintf("%+v", test), func(t *testing.T) {
			if *fstest.SizeLimit > 0 && int64(test.size) > *fstest.SizeLimit {
				t.Skipf("exceeded file size limit %d > %d", test.size, *fstest.SizeLimit)
			}
			var err error
			contents := random.String(test.size)
			t1 := fstest.Time("2001-02-03T04:05:06.499999999Z")
			file1 := r.WriteObject(context.Background(), "file1", contents, t1)
			fstest.CheckItems(t, r.Fremote, file1)
			fstest.CheckItems(t, r.Flocal)

			src, err := r.Fremote.NewObject(context.Background(), "file1")
			require.NoError(t, err)
			accounting.GlobalStats().ResetCounters()
			tr := accounting.GlobalStats().NewTransfer(src)

			defer func() {
				tr.Done(err)
			}()
			dst, err := multiThreadCopy(context.Background(), r.Flocal, "file1", src, 2, tr)
			require.NoError(t, err)
			assert.Equal(t, src.Size(), dst.Size())
			assert.Equal(t, "file1", dst.Remote())

			fstest.CheckListingWithPrecision(t, r.Flocal, []fstest.Item{file1}, nil, fs.GetModifyWindow(r.Flocal, r.Fremote))
			require.NoError(t, dst.Remove(context.Background()))
		})
	}

}
<|endoftext|>