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

package cluster

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/docker/machine/drivers/virtualbox"
	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/host"
	"github.com/kubernetes/minikube/cli/constants"
	"rsprd.com/localkube/pkg/localkubectl"
)

// StartHost starts a host VM.
func StartHost(api libmachine.API) (*host.Host, error) {
	if exists, err := api.Exists(constants.MachineName); err != nil {
		return nil, fmt.Errorf("Error checking if host exists: %s", err)
	} else if exists {
		log.Println("Machine exists!")
		h, err := api.Load(constants.MachineName)
		if err != nil {
			return nil, fmt.Errorf("Error loading existing host.")
		}
		return h, nil
	} else {
		return createHost(api)
	}
}

// StartCluster starts as k8s cluster on the specified Host.
func StartCluster(h *host.Host) (string, error) {
	host, err := h.Driver.GetURL()
	if err != nil {
		return "", err
	}
	kubeHost := strings.Replace(host, "tcp://", "http://", -1)
	kubeHost = strings.Replace(kubeHost, ":2376", ":8080", -1)

	os.Setenv("DOCKER_HOST", host)
	os.Setenv("DOCKER_CERT_PATH", constants.MakeMiniPath("certs"))
	os.Setenv("DOCKER_TLS_VERIFY", "1")
	ctlr, err := localkubectl.NewControllerFromEnv(os.Stdout)
	if err != nil {
		log.Panicf("Error creating controller: %s", err)
	}

	// Look for an existing container
	ctrID, running, err := ctlr.OnlyLocalkubeCtr()
	if running {
		log.Println("Localkube is already running")
		return kubeHost, nil
	}
	if err == localkubectl.ErrNoContainer {
		// If container doesn't exist, create
		ctrID, running, err = ctlr.CreateCtr(localkubectl.LocalkubeContainerName, "latest")
		if err != nil {
			return "", err
		}
		// Start container.
		err = ctlr.StartCtr(ctrID, "")
		if err != nil {
			return "", err
		}
	}
	return kubeHost, nil
}

func createHost(api libmachine.API) (*host.Host, error) {
	driver := virtualbox.NewDriver(constants.MachineName, constants.Minipath)
	driver.Boot2DockerURL = "https://storage.googleapis.com/tinykube/boot2docker.iso"
	data, err := json.Marshal(driver)
	if err != nil {
		return nil, err
	}

	driverName := "virtualbox"
	h, err := api.NewHost(driverName, data)
	if err != nil {
		return nil, fmt.Errorf("Error creating new host: %s", err)
	}

	h.HostOptions.AuthOptions.CertDir = constants.Minipath
	h.HostOptions.AuthOptions.StorePath = constants.Minipath

	if err := api.Create(h); err != nil {
		// Wait for all the logs to reach the client
		time.Sleep(2 * time.Second)
		return nil, fmt.Errorf("Error creating. %s", err)
	}

	if err := api.Save(h); err != nil {
		return nil, fmt.Errorf("Error attempting to save store: %s", err)
	}
	return h, nil
}
<commit_msg>Stop using localkubectl. Start localkube via ssh commands, outside the container.<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cluster

import (
	"encoding/json"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/docker/machine/drivers/virtualbox"
	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/host"
	"github.com/kubernetes/minikube/cli/constants"
)

// StartHost starts a host VM.
func StartHost(api libmachine.API) (*host.Host, error) {
	if exists, err := api.Exists(constants.MachineName); err != nil {
		return nil, fmt.Errorf("Error checking if host exists: %s", err)
	} else if exists {
		log.Println("Machine exists!")
		h, err := api.Load(constants.MachineName)
		if err != nil {
			return nil, fmt.Errorf("Error loading existing host.")
		}
		return h, nil
	} else {
		return createHost(api)
	}
}

// StartCluster starts as k8s cluster on the specified Host.
func StartCluster(h *host.Host) (string, error) {
	host, err := h.Driver.GetURL()
	if err != nil {
		return "", err
	}
	kubeHost := strings.Replace(host, "tcp://", "http://", -1)
	kubeHost = strings.Replace(kubeHost, ":2376", ":8080", -1)

	for _, cmd := range []string{
		// Download and install weave, if it doesn't exist.
		`if [ ! -e /usr/local/bin/weave ];
		 then
		   sudo curl -L git.io/weave -o /usr/local/bin/weave
		   sudo chmod a+x /usr/local/bin/weave;
		 fi`,
		// Download and install localkube, if it doesn't exist yet.
		`if [ ! -e /usr/local/bin/localkube ];
		 then
		   sudo curl -L https://github.com/redspread/localkube/releases/download/v1.2.1-v1/localkube-linux -o /usr/local/bin/localkube
		   sudo chmod a+x /usr/local/bin/localkube;
		 fi`,
		// Start weave.
		"weave launch-router",
		"weave launch-proxy --without-dns --rewrite-inspect",
		"weave expose -h \"localkube.weave.local\"",
		// Localkube assumes containerized kubelet, which looks at /rootfs.
		"if [ ! -e /rootfs ]; then sudo ln -s / /rootfs; fi",
		// Run with nohup so it stays up. Redirect logs to useful places.
		"PATH=/usr/local/sbin:$PATH nohup sudo /usr/local/bin/localkube start > /var/log/localkube.out 2> /var/log/localkube.err < /dev/null &"} {
		output, err := h.RunSSHCommand(cmd)
		log.Println(output)
		if err != nil {
			return "", err
		}
	}

	return kubeHost, nil
}

func createHost(api libmachine.API) (*host.Host, error) {
	driver := virtualbox.NewDriver(constants.MachineName, constants.Minipath)
	driver.Boot2DockerURL = "https://storage.googleapis.com/tinykube/boot2docker.iso"
	data, err := json.Marshal(driver)
	if err != nil {
		return nil, err
	}

	driverName := "virtualbox"
	h, err := api.NewHost(driverName, data)
	if err != nil {
		return nil, fmt.Errorf("Error creating new host: %s", err)
	}

	h.HostOptions.AuthOptions.CertDir = constants.Minipath
	h.HostOptions.AuthOptions.StorePath = constants.Minipath

	if err := api.Create(h); err != nil {
		// Wait for all the logs to reach the client
		time.Sleep(2 * time.Second)
		return nil, fmt.Errorf("Error creating. %s", err)
	}

	if err := api.Save(h); err != nil {
		return nil, fmt.Errorf("Error attempting to save store: %s", err)
	}
	return h, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"archive/tar"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/inconshreveable/log15"
	"github.com/spacemonkeygo/errors"
	"github.com/spacemonkeygo/errors/try"

	"polydawn.net/repeatr/executor/util"
	"polydawn.net/repeatr/io"
	"polydawn.net/repeatr/io/filter"
	"polydawn.net/repeatr/lib/fshash"
	"polydawn.net/repeatr/lib/treewalk"
)

func ExploreCommandPattern(stdout, stderr io.Writer) cli.Command {
	return cli.Command{
		Name:  "explore",
		Usage: "describe a ware and the metadata of its contents -- human readable; also useful for piping into diff to discover why two almost-identical wares aren't.",
		// sub-subcommands?
		//   - repeatr explore item [item]
		//        Produces a manifest of every file in the named item, their properties, and their hashes.  Output is structed as tab-delimited values -- you may feed it to an external `diff` program to compare one item with another; or, for easier reading, try piping it to `column -t`.
		//   - repeatr explore diff [item1] [item2]
		//        ... see, it's right about here that i start losing it in terms of how we should express object getting.  a bunch of flags named "--hash1" and "--hash2" are the obvious answer, but i pine for a more pleasant mechanism.
		//   - repeatr explore run [formula] [--output=name]
		//        As per `repeatr explore item`, but runs the formula and then immediately explores its output.
		//   - repeatr explore repeat [formula]
		//        Runs the given formula twice.  Checks that all the conjectured outputs are the same, exiting with a 1 and exploring diffs if they exist; exiting 0 if no diffs.
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "kind",
				Usage: "What kind of data storage format to work with.",
			},
			cli.StringFlag{
				Name:  "hash",
				Usage: "The ID of the object to explore.",
			},
			cli.StringFlag{
				Name:  "where",
				Usage: "A URL giving coordinates to a warehouse where repeatr should find the object to explore.",
			},
		},
		Action: func(ctx *cli.Context) {
			if ctx.String("kind") == "" {
				panic(Error.New("%q is a required parameter", "kind"))
			}
			if ctx.String("hash") == "" {
				panic(Error.New("%q is a required parameter", "hash"))
			}
			if ctx.String("where") == "" {
				panic(Error.New("%q is a required parameter", "where"))
			}

			log := log15.New()
			log.SetHandler(log15.StreamHandler(stderr, log15.TerminalFormat()))

			try.Do(func() {
				// Materialize the things.
				arena := util.DefaultTransmat().Materialize(
					integrity.TransmatKind(ctx.String("kind")),
					integrity.CommitID(ctx.String("hash")),
					[]integrity.SiloURI{integrity.SiloURI(ctx.String("where"))},
					log,
				)
				defer arena.Teardown()

				// Scan the whole arena contents back into a bucket of hashes and metadata.
				//  (If warehouses exposed their Buckets, that'd be handy.  But of course, not everyone uses those, so.)
				bucket := &fshash.MemoryBucket{}
				hasherFactory := sha512.New384
				filterset := filter.FilterSet{}
				if err := fshash.FillBucket(arena.Path(), "", bucket, filterset, hasherFactory); err != nil {
					panic(err)
				}

				// Emit TDV.  (We'll quote&escape filenames so null-terminated lines aren't necessary -- this is meant for human consumption after all.)
				// Treewalk to the rescue, again.
				preVisit := func(node treewalk.Node) error {
					record := node.(fshash.RecordIterator).Record()
					m := record.Metadata
					// compute optional values
					var freehandValues []string
					if m.Linkname != "" {
						freehandValues = append(freehandValues, fmt.Sprintf("link:%q", m.Linkname))
					}
					if m.Typeflag == tar.TypeBlock || m.Typeflag == tar.TypeChar {
						freehandValues = append(freehandValues, fmt.Sprintf("major:%d", m.Devmajor))
						freehandValues = append(freehandValues, fmt.Sprintf("minor:%d", m.Devminor))
					} else if m.Typeflag == tar.TypeReg {
						freehandValues = append(freehandValues, fmt.Sprintf("hash:%s", base64.URLEncoding.EncodeToString(record.ContentHash)))
						freehandValues = append(freehandValues, fmt.Sprintf("len:%d", m.Size))
					}
					xattrsLen := len(m.Xattrs)
					if xattrsLen > 0 {
						sorted := make([]string, 0, xattrsLen)
						for k, v := range m.Xattrs {
							sorted = append(sorted, fmt.Sprintf("%q:%q", k, v))
						}
						sort.Strings(sorted)
						freehandValues = append(freehandValues, fmt.Sprintf("xattrs:[%s]", strings.Join(sorted, ",")))
					}
					// plug and chug
					fmt.Fprintf(stdout,
						"%q\t%c\t%#o\t%d\t%d\t%s\t%s\n",
						m.Name,
						m.Typeflag,
						m.Mode&07777,
						m.Uid,
						m.Gid,
						m.ModTime.UTC(),
						strings.Join(freehandValues, ","),
					)
					return nil
				}
				if err := treewalk.Walk(bucket.Iterator(), preVisit, nil); err != nil {
					panic(err)
				}
			}).Catch(integrity.ConfigError, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Catch(integrity.WarehouseUnavailableError, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Catch(integrity.DataDNE, func(err *errors.Error) {
				panic(Error.New("%s", err.Message()))
			}).Done()
		},
	}
}
<commit_msg>Begin restructuring `explore` into more subcommand<commit_after>package cli

import (
	"archive/tar"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"io"
	"sort"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/inconshreveable/log15"
	"github.com/spacemonkeygo/errors"
	"github.com/spacemonkeygo/errors/try"

	"polydawn.net/repeatr/executor/util"
	"polydawn.net/repeatr/io"
	"polydawn.net/repeatr/io/filter"
	"polydawn.net/repeatr/lib/fshash"
	"polydawn.net/repeatr/lib/treewalk"
)

func ExploreCommandPattern(stdout, stderr io.Writer) cli.Command {
	return cli.Command{
		Name:  "explore",
		Usage: "describe a ware and the metadata of its contents, or a filesystem",
		Description: strings.Join([]string{
			"`repeatr explore` produces a human-readable manifest of every file in the named item",
			"(either wares or local filesystems may be examined), their properties, and their hashes.",
			"\n\n  ",
			"Output is structed as tab-delimited values -- you may feed it to an external `diff` program",
			"to compare one item with another; or, for easier reading, try piping it to `column -t`",
		}, " "),
		Subcommands: []cli.Command{
			{
				Name:  "ware",
				Usage: "explore a ware from a warehouse",
				Flags: []cli.Flag{
					cli.StringFlag{
						Name:  "kind",
						Usage: "What kind of data storage format to work with.",
					},
					cli.StringFlag{
						Name:  "hash",
						Usage: "The ID of the object to explore.",
					},
					cli.StringFlag{
						Name:  "where",
						Usage: "A URL giving coordinates to a warehouse where repeatr should find the object to explore.",
					},
				},
				Action: func(ctx *cli.Context) {
					if ctx.String("kind") == "" {
						panic(Error.New("%q is a required parameter", "kind"))
					}
					if ctx.String("hash") == "" {
						panic(Error.New("%q is a required parameter", "hash"))
					}
					if ctx.String("where") == "" {
						panic(Error.New("%q is a required parameter", "where"))
					}

					log := log15.New()
					log.SetHandler(log15.StreamHandler(stderr, log15.TerminalFormat()))

					try.Do(func() {
						// Materialize the things.
						arena := util.DefaultTransmat().Materialize(
							integrity.TransmatKind(ctx.String("kind")),
							integrity.CommitID(ctx.String("hash")),
							[]integrity.SiloURI{integrity.SiloURI(ctx.String("where"))},
							log,
						)
						defer arena.Teardown()
						// Examine 'em.
						examinePath(arena.Path(), stdout)
					}).Catch(integrity.ConfigError, func(err *errors.Error) {
						panic(Error.New("%s", err.Message()))
					}).Catch(integrity.WarehouseUnavailableError, func(err *errors.Error) {
						panic(Error.New("%s", err.Message()))
					}).Catch(integrity.DataDNE, func(err *errors.Error) {
						panic(Error.New("%s", err.Message()))
					}).Done()
				},
			},
			{
				Name:  "file",
				Usage: "explore a local filesystem",
				Action: func(ctx *cli.Context) {
					panic("NYI")
				},
			},
			// Other kinds of explore sub-command that may come later:
			//   - repeatr explore diff [item1] [item2]
			//        ... see, it's right about here that i start losing it in terms of how we should express object getting.  a bunch of flags named "--hash1" and "--hash2" are the obvious answer, but i pine for a more pleasant mechanism.
			//   - repeatr explore run [formula] [--output=name]
			//        As per `repeatr explore item`, but runs the formula and then immediately explores its output.
			//   - repeatr explore repeat [formula]
			//        Runs the given formula twice.  Checks that all the conjectured outputs are the same, exiting with a 1 and exploring diffs if they exist; exiting 0 if no diffs.
		},
	}
}

func examinePath(thePath string, stdout io.Writer) {
	// Scan the whole arena contents back into a bucket of hashes and metadata.
	//  (If warehouses exposed their Buckets, that'd be handy.  But of course, not everyone uses those, so.)
	bucket := &fshash.MemoryBucket{}
	hasherFactory := sha512.New384
	filterset := filter.FilterSet{}
	if err := fshash.FillBucket(thePath, "", bucket, filterset, hasherFactory); err != nil {
		panic(err)
	}

	// Emit TDV.  (We'll quote&escape filenames so null-terminated lines aren't necessary -- this is meant for human consumption after all.)
	// Treewalk to the rescue, again.
	preVisit := func(node treewalk.Node) error {
		record := node.(fshash.RecordIterator).Record()
		m := record.Metadata
		// compute optional values
		var freehandValues []string
		if m.Linkname != "" {
			freehandValues = append(freehandValues, fmt.Sprintf("link:%q", m.Linkname))
		}
		if m.Typeflag == tar.TypeBlock || m.Typeflag == tar.TypeChar {
			freehandValues = append(freehandValues, fmt.Sprintf("major:%d", m.Devmajor))
			freehandValues = append(freehandValues, fmt.Sprintf("minor:%d", m.Devminor))
		} else if m.Typeflag == tar.TypeReg {
			freehandValues = append(freehandValues, fmt.Sprintf("hash:%s", base64.URLEncoding.EncodeToString(record.ContentHash)))
			freehandValues = append(freehandValues, fmt.Sprintf("len:%d", m.Size))
		}
		xattrsLen := len(m.Xattrs)
		if xattrsLen > 0 {
			sorted := make([]string, 0, xattrsLen)
			for k, v := range m.Xattrs {
				sorted = append(sorted, fmt.Sprintf("%q:%q", k, v))
			}
			sort.Strings(sorted)
			freehandValues = append(freehandValues, fmt.Sprintf("xattrs:[%s]", strings.Join(sorted, ",")))
		}
		// plug and chug
		fmt.Fprintf(stdout,
			"%q\t%c\t%#o\t%d\t%d\t%s\t%s\n",
			m.Name,
			m.Typeflag,
			m.Mode&07777,
			m.Uid,
			m.Gid,
			m.ModTime.UTC(),
			strings.Join(freehandValues, ","),
		)
		return nil
	}
	if err := treewalk.Walk(bucket.Iterator(), preVisit, nil); err != nil {
		panic(err)
	}
}
<|endoftext|>


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

package p

import "fmt"

func permToString(perm uint32) string {
	ret := ""

	if perm&DMDIR != 0 {
		ret += "d"
	}

	if perm&DMAPPEND != 0 {
		ret += "a"
	}

	if perm&DMAUTH != 0 {
		ret += "A"
	}

	if perm&DMEXCL != 0 {
		ret += "l"
	}

	if perm&DMTMP != 0 {
		ret += "t"
	}

	if perm&DMDEVICE != 0 {
		ret += "D"
	}

	if perm&DMSOCKET != 0 {
		ret += "S"
	}

	if perm&DMNAMEDPIPE != 0 {
		ret += "P"
	}

	if perm&DMSYMLINK != 0 {
		ret += "L"
	}

	ret += fmt.Sprintf("%o", perm&0777)
	return ret
}

func (qid *Qid) String() string {
	b := ""
	if qid.Type&QTDIR != 0 {
		b += "d"
	}
	if qid.Type&QTAPPEND != 0 {
		b += "a"
	}
	if qid.Type&QTAUTH != 0 {
		b += "A"
	}
	if qid.Type&QTEXCL != 0 {
		b += "l"
	}
	if qid.Type&QTTMP != 0 {
		b += "t"
	}
	if qid.Type&QTSYMLINK != 0 {
		b += "L"
	}

	return fmt.Sprintf("(%x %x '%s')", qid.Path, qid.Version, b)
}

func (d *Dir) String() string {
	ret := fmt.Sprintf("'%s' '%s' '%s' '%s' q ", d.Name, d.Uid, d.Gid, d.Muid)
	ret += d.Qid.String() + " m " + permToString(d.Mode)
	ret += fmt.Sprintf(" at %d mt %d l %d t %d d %d", d.Atime, d.Mtime,
		d.Length, d.Type, d.Dev)

	/* dotu ? */
	ret += " ext " + d.Ext

	return ret
}

func (fc *Fcall) String() string {
	ret := ""

	switch fc.Type {
	default:
		ret = fmt.Sprintf("invalid call: %d", fc.Type)
	case Tversion:
		ret = fmt.Sprintf("Tversion tag %d msize %d version '%s'", fc.Tag, fc.Msize, fc.Version)
	case Rversion:
		ret = fmt.Sprintf("Rversion tag %d msize %d version '%s'", fc.Tag, fc.Msize, fc.Version)
	case Tauth:
		ret = fmt.Sprintf("Tauth tag %d afid %d uname '%s' nuname %d aname '%s'",
			fc.Tag, fc.Afid, fc.Uname, fc.Unamenum, fc.Aname)
	case Rauth:
		ret = fmt.Sprintf("Rauth tag %d aqid %v", fc.Tag, fc.Qid)
	case Rattach:
		ret = fmt.Sprintf("Rattach tag %d aqid %v", fc.Tag, fc.Qid)
	case Tattach:
		ret = fmt.Sprintf("Tattach tag %d fid %d afid %d uname '%s' nuname %d aname '%s'",
			fc.Tag, fc.Fid, fc.Afid, fc.Uname, fc.Unamenum, fc.Aname)
	case Tflush:
		ret = fmt.Sprintf("Tflush tag %d oldtag %d", fc.Tag, fc.Oldtag)
	case Rerror:
		ret = fmt.Sprintf("Rerror tag %d ename '%s' ecode %d", fc.Tag, fc.Error, fc.Errornum)
	case Twalk:
		ret = fmt.Sprintf("Twalk tag %d fid %d newfid %d ", fc.Tag, fc.Fid, fc.Newfid)
		for i := 0; i < len(fc.Wname); i++ {
			ret += fmt.Sprintf("%d:'%s' ", i, fc.Wname[i])
		}
	case Rwalk:
		ret = fmt.Sprintf("Rwalk tag %d ", fc.Tag)
		for i := 0; i < len(fc.Wqid); i++ {
			ret += fmt.Sprintf("%v ", &fc.Wqid[i])
		}
	case Topen:
		ret = fmt.Sprintf("Topen tag %d fid %d mode %x", fc.Tag, fc.Fid, fc.Mode)
	case Ropen:
		ret = fmt.Sprintf("Ropen tag %d qid %v iounit %d", fc.Tag, &fc.Qid, fc.Iounit)
	case Rcreate:
		ret = fmt.Sprintf("Rcreate tag %d qid %v iounit %d", fc.Tag, fc.Qid, fc.Iounit)
	case Tcreate:
		ret = fmt.Sprintf("Tcreate tag %d fid %d name '%s' perm ", fc.Tag, fc.Fid, fc.Name)
		ret += permToString(fc.Perm)
		ret += fmt.Sprintf(" mode %x ", fc.Mode)
	case Tread:
		ret = fmt.Sprintf("Tread tag %d fid %d offset %d count %d", fc.Tag, fc.Fid, fc.Offset, fc.Count)
	case Rread:
		ret = fmt.Sprintf("Rread tag %d count %d", fc.Tag, fc.Count)
	case Twrite:
		ret = fmt.Sprintf("Twrite tag %d fid %d offset %d count %d", fc.Tag, fc.Fid, fc.Offset, fc.Count)
	case Rwrite:
		ret = fmt.Sprintf("Rwrite tag %d count %d", fc.Tag, fc.Count)
	case Tclunk:
		ret = fmt.Sprintf("Tclunk tag %d fid %d", fc.Tag, fc.Fid)
	case Rclunk:
		ret = fmt.Sprintf("Rclunk tag %d", fc.Tag)
	case Tremove:
		ret = fmt.Sprintf("Tremove tag %d fid %d", fc.Tag, fc.Fid)
	case Tstat:
		ret = fmt.Sprintf("Tstat tag %d fid %d", fc.Tag, fc.Fid)
	case Rstat:
		ret = fmt.Sprintf("Rstat tag %d st (%v)", fc.Tag, &fc.Dir)
	case Twstat:
		ret = fmt.Sprintf("Twstat tag %d fid %d st (%v)", fc.Tag, fc.Fid, &fc.Dir)
	case Rflush:
		ret = fmt.Sprintf("Rflush tag %d", fc.Tag)
	case Rremove:
		ret = fmt.Sprintf("Rremove tag %d", fc.Tag)
	case Rwstat:
		ret = fmt.Sprintf("Rwstat tag %d", fc.Tag)
	}

	return ret
}
<commit_msg>Fix from dadkins: display Qids properly.<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package p

import "fmt"

func permToString(perm uint32) string {
	ret := ""

	if perm&DMDIR != 0 {
		ret += "d"
	}

	if perm&DMAPPEND != 0 {
		ret += "a"
	}

	if perm&DMAUTH != 0 {
		ret += "A"
	}

	if perm&DMEXCL != 0 {
		ret += "l"
	}

	if perm&DMTMP != 0 {
		ret += "t"
	}

	if perm&DMDEVICE != 0 {
		ret += "D"
	}

	if perm&DMSOCKET != 0 {
		ret += "S"
	}

	if perm&DMNAMEDPIPE != 0 {
		ret += "P"
	}

	if perm&DMSYMLINK != 0 {
		ret += "L"
	}

	ret += fmt.Sprintf("%o", perm&0777)
	return ret
}

func (qid *Qid) String() string {
	b := ""
	if qid.Type&QTDIR != 0 {
		b += "d"
	}
	if qid.Type&QTAPPEND != 0 {
		b += "a"
	}
	if qid.Type&QTAUTH != 0 {
		b += "A"
	}
	if qid.Type&QTEXCL != 0 {
		b += "l"
	}
	if qid.Type&QTTMP != 0 {
		b += "t"
	}
	if qid.Type&QTSYMLINK != 0 {
		b += "L"
	}

	return fmt.Sprintf("(%x %x '%s')", qid.Path, qid.Version, b)
}

func (d *Dir) String() string {
	ret := fmt.Sprintf("'%s' '%s' '%s' '%s' q ", d.Name, d.Uid, d.Gid, d.Muid)
	ret += d.Qid.String() + " m " + permToString(d.Mode)
	ret += fmt.Sprintf(" at %d mt %d l %d t %d d %d", d.Atime, d.Mtime,
		d.Length, d.Type, d.Dev)

	/* dotu ? */
	ret += " ext " + d.Ext

	return ret
}

func (fc *Fcall) String() string {
	ret := ""

	switch fc.Type {
	default:
		ret = fmt.Sprintf("invalid call: %d", fc.Type)
	case Tversion:
		ret = fmt.Sprintf("Tversion tag %d msize %d version '%s'", fc.Tag, fc.Msize, fc.Version)
	case Rversion:
		ret = fmt.Sprintf("Rversion tag %d msize %d version '%s'", fc.Tag, fc.Msize, fc.Version)
	case Tauth:
		ret = fmt.Sprintf("Tauth tag %d afid %d uname '%s' nuname %d aname '%s'",
			fc.Tag, fc.Afid, fc.Uname, fc.Unamenum, fc.Aname)
	case Rauth:
		ret = fmt.Sprintf("Rauth tag %d aqid %v", fc.Tag, &fc.Qid)
	case Rattach:
		ret = fmt.Sprintf("Rattach tag %d aqid %v", fc.Tag, &fc.Qid)
	case Tattach:
		ret = fmt.Sprintf("Tattach tag %d fid %d afid %d uname '%s' nuname %d aname '%s'",
			fc.Tag, fc.Fid, fc.Afid, fc.Uname, fc.Unamenum, fc.Aname)
	case Tflush:
		ret = fmt.Sprintf("Tflush tag %d oldtag %d", fc.Tag, fc.Oldtag)
	case Rerror:
		ret = fmt.Sprintf("Rerror tag %d ename '%s' ecode %d", fc.Tag, fc.Error, fc.Errornum)
	case Twalk:
		ret = fmt.Sprintf("Twalk tag %d fid %d newfid %d ", fc.Tag, fc.Fid, fc.Newfid)
		for i := 0; i < len(fc.Wname); i++ {
			ret += fmt.Sprintf("%d:'%s' ", i, fc.Wname[i])
		}
	case Rwalk:
		ret = fmt.Sprintf("Rwalk tag %d ", fc.Tag)
		for i := 0; i < len(fc.Wqid); i++ {
			ret += fmt.Sprintf("%v ", &fc.Wqid[i])
		}
	case Topen:
		ret = fmt.Sprintf("Topen tag %d fid %d mode %x", fc.Tag, fc.Fid, fc.Mode)
	case Ropen:
		ret = fmt.Sprintf("Ropen tag %d qid %v iounit %d", fc.Tag, &fc.Qid, fc.Iounit)
	case Rcreate:
		ret = fmt.Sprintf("Rcreate tag %d qid %v iounit %d", fc.Tag, &fc.Qid, fc.Iounit)
	case Tcreate:
		ret = fmt.Sprintf("Tcreate tag %d fid %d name '%s' perm ", fc.Tag, fc.Fid, fc.Name)
		ret += permToString(fc.Perm)
		ret += fmt.Sprintf(" mode %x ", fc.Mode)
	case Tread:
		ret = fmt.Sprintf("Tread tag %d fid %d offset %d count %d", fc.Tag, fc.Fid, fc.Offset, fc.Count)
	case Rread:
		ret = fmt.Sprintf("Rread tag %d count %d", fc.Tag, fc.Count)
	case Twrite:
		ret = fmt.Sprintf("Twrite tag %d fid %d offset %d count %d", fc.Tag, fc.Fid, fc.Offset, fc.Count)
	case Rwrite:
		ret = fmt.Sprintf("Rwrite tag %d count %d", fc.Tag, fc.Count)
	case Tclunk:
		ret = fmt.Sprintf("Tclunk tag %d fid %d", fc.Tag, fc.Fid)
	case Rclunk:
		ret = fmt.Sprintf("Rclunk tag %d", fc.Tag)
	case Tremove:
		ret = fmt.Sprintf("Tremove tag %d fid %d", fc.Tag, fc.Fid)
	case Tstat:
		ret = fmt.Sprintf("Tstat tag %d fid %d", fc.Tag, fc.Fid)
	case Rstat:
		ret = fmt.Sprintf("Rstat tag %d st (%v)", fc.Tag, &fc.Dir)
	case Twstat:
		ret = fmt.Sprintf("Twstat tag %d fid %d st (%v)", fc.Tag, fc.Fid, &fc.Dir)
	case Rflush:
		ret = fmt.Sprintf("Rflush tag %d", fc.Tag)
	case Rremove:
		ret = fmt.Sprintf("Rremove tag %d", fc.Tag)
	case Rwstat:
		ret = fmt.Sprintf("Rwstat tag %d", fc.Tag)
	}

	return ret
}
<|endoftext|>


<commit_before>package fastpass

import (
	"sort"

	"github.com/renstrom/fuzzysearch/fuzzy"
)

//Entries is a set of entries
type Entries []*Entry

//FuzzyMatch returns all entries with names fuzzy matching search
func (es Entries) FuzzyMatch(search string) (ret Entries) {
	for _, entry := range es {
		if fuzzy.Match(search, entry.Name) {
			ret = append(ret, entry)
		}
	}
	return
}

//DeleteByName deletes an entry from es and returns a new slice
func (es Entries) DeleteByName(name string) (cleaned Entries) {
	for _, e := range es {
		if e.Name == name {
			continue
		}
		cleaned = append(cleaned, e)
	}
	return
}

//FindByName finds an entry by it's name.
//It returns nil if no entry was found.
func (es Entries) FindByName(name string) *Entry {
	for _, e := range es {
		if e.Name == name {
			return e
		}
	}
	return nil
}

//SortByName sorts es by name
func (es Entries) SortByName() Entries {
	sort.Slice(es, func(i, j int) bool {
		return es[i].Name < es[j].Name
	})
	return es
}

//SortByHits sorts es by hits
func (es Entries) SortByHits() Entries {
	sort.Slice(es, func(i, j int) bool {
		return es[i].Stats.Hits > es[j].Stats.Hits
	})
	return es
}

//SortByBestMatch tries to sort entries by best match
func (es Entries) SortByBestMatch(search string) Entries {
	sort.Slice(es, func(i, j int) bool {
		iDistance, jDistance := fuzzy.RankMatch(search, es[i].Name), fuzzy.RankMatch(search, es[j].Name)

		if iDistance < 0 {
			return false
		}
		if iDistance == 0 {
			return true
		}
		if jDistance == 0 {
			return false
		}

		iScore := (float64(es[i].Stats.Hits) / (float64(iDistance) / float64(len(es[i].Name))))
		jScore := (float64(es[j].Stats.Hits) / (float64(jDistance) / float64(len(es[j].Name))))
		return iScore > jScore
	})
	return es
}

// //FilterByTag returns all entries with a certain tag
// func (entries Entries) FilterByTag(tag string) Entries {
// 	var matches Entries
// 	for _, e := range entries {
// 		if e.HasTag(tag) {
// 			matches = append(matches, e)
// 		}
// 	}
// 	return matches
// }
<commit_msg>cache distances on search<commit_after>package fastpass

import (
	"sort"

	"github.com/renstrom/fuzzysearch/fuzzy"
)

//Entries is a set of entries
type Entries []*Entry

//FuzzyMatch returns all entries with names fuzzy matching search
func (es Entries) FuzzyMatch(search string) (ret Entries) {
	for _, entry := range es {
		if fuzzy.Match(search, entry.Name) {
			ret = append(ret, entry)
		}
	}
	return
}

//DeleteByName deletes an entry from es and returns a new slice
func (es Entries) DeleteByName(name string) (cleaned Entries) {
	for _, e := range es {
		if e.Name == name {
			continue
		}
		cleaned = append(cleaned, e)
	}
	return
}

//FindByName finds an entry by it's name.
//It returns nil if no entry was found.
func (es Entries) FindByName(name string) *Entry {
	for _, e := range es {
		if e.Name == name {
			return e
		}
	}
	return nil
}

//SortByName sorts es by name
func (es Entries) SortByName() Entries {
	sort.Slice(es, func(i, j int) bool {
		return es[i].Name < es[j].Name
	})
	return es
}

//SortByHits sorts es by hits
func (es Entries) SortByHits() Entries {
	sort.Slice(es, func(i, j int) bool {
		return es[i].Stats.Hits > es[j].Stats.Hits
	})
	return es
}

//SortByBestMatch tries to sort entries by best match
func (es Entries) SortByBestMatch(search string) Entries {
	distances := make([]int, len(es))
	for i, e := range es {
		distances[i] = fuzzy.RankMatch(search, e.Name)
	}
	sort.Slice(es, func(i, j int) bool {
		iDistance, jDistance := distances[i], distances[j]

		if iDistance < 0 {
			return false
		}
		if iDistance == 0 {
			return true
		}
		if jDistance == 0 {
			return false
		}

		iScore := (float64(es[i].Stats.Hits) / (float64(iDistance) / float64(len(es[i].Name))))
		jScore := (float64(es[j].Stats.Hits) / (float64(jDistance) / float64(len(es[j].Name))))
		return iScore > jScore
	})
	return es
}

// //FilterByTag returns all entries with a certain tag
// func (entries Entries) FilterByTag(tag string) Entries {
// 	var matches Entries
// 	for _, e := range entries {
// 		if e.HasTag(tag) {
// 			matches = append(matches, e)
// 		}
// 	}
// 	return matches
// }
<|endoftext|>


<commit_before>package env

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.ugent.be/unigornel/config"

	"github.com/urfave/cli"
)

const (
	MiniOSRootEnv = "UNIGORNEL_MINIOS"
)

const (
	configFullFlagName = "config"
)

func configFlag() cli.Flag {
	return cli.StringFlag{
		Name:   configFullFlagName + ", c",
		EnvVar: "UNIGORNEL_CONFIG",
		Usage:  "path to the configuration file (yaml)",
	}
}

func Env() cli.Command {
	return cli.Command{
		Name:  "env",
		Usage: "setup your shell",
		Flags: []cli.Flag{
			configFlag(),
		},
		Action: func(ctx *cli.Context) error {
			options := EnvOptions{
				ConfigFile: ctx.String(configFullFlagName),
			}

			if err := env(options); err != nil {
				return cli.NewExitError("error: "+err.Error(), 1)
			}
			return nil
		},
	}
}

func RequireMiniOSRoot() (s string, err error) {
	s = os.Getenv(MiniOSRootEnv)
	if s == "" {
		err = cli.NewExitError("error: environment variable UNIGORNEL_MINIOS not set", 1)
	}
	return
}

func GetConfig(configPath string) (config.Config, error) {
	empty := config.Config{}

	s := configPath
	if s == "" {
		u, err := user.Current()
		if err != nil {
			return empty, err
		}
		s = path.Join(u.HomeDir, ".unigornel.yaml")
	}

	data, err := ioutil.ReadFile(s)
	if err != nil {
		return empty, err
	}

	c, err := config.ParseConfig(data)
	if err != nil {
		return empty, err
	}
	return c, nil
}

type EnvOptions struct {
	ConfigFile string
}

func env(options EnvOptions) error {
	config, err := GetConfig(options.ConfigFile)
	if err != nil {
		return err
	}
	for _, v := range configToEnvVars(config) {
		fmt.Println(export(v))
	}
	return nil
}

type envVar struct {
	Name  string
	Value string
}

func export(v envVar) string {
	return "export " + v.Name + "=\"" + v.Value + "\""
}

func configToEnvVars(c config.Config) []envVar {
	return []envVar{
		{
			Name:  "GOROOT",
			Value: c.GoRoot,
		},
		{
			Name:  MiniOSRootEnv,
			Value: c.MiniOS,
		},
	}
}
<commit_msg>Also update PATH with `unigornel env`<commit_after>package env

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"

	"github.ugent.be/unigornel/config"

	"github.com/urfave/cli"
)

const (
	MiniOSRootEnv = "UNIGORNEL_MINIOS"
)

const (
	configFullFlagName = "config"
)

func configFlag() cli.Flag {
	return cli.StringFlag{
		Name:   configFullFlagName + ", c",
		EnvVar: "UNIGORNEL_CONFIG",
		Usage:  "path to the configuration file (yaml)",
	}
}

func Env() cli.Command {
	return cli.Command{
		Name:  "env",
		Usage: "setup your shell",
		Flags: []cli.Flag{
			configFlag(),
		},
		Action: func(ctx *cli.Context) error {
			options := EnvOptions{
				ConfigFile: ctx.String(configFullFlagName),
			}

			if err := env(options); err != nil {
				return cli.NewExitError("error: "+err.Error(), 1)
			}
			return nil
		},
	}
}

func RequireMiniOSRoot() (s string, err error) {
	s = os.Getenv(MiniOSRootEnv)
	if s == "" {
		err = cli.NewExitError("error: environment variable UNIGORNEL_MINIOS not set", 1)
	}
	return
}

func GetConfig(configPath string) (config.Config, error) {
	empty := config.Config{}

	s := configPath
	if s == "" {
		u, err := user.Current()
		if err != nil {
			return empty, err
		}
		s = path.Join(u.HomeDir, ".unigornel.yaml")
	}

	data, err := ioutil.ReadFile(s)
	if err != nil {
		return empty, err
	}

	c, err := config.ParseConfig(data)
	if err != nil {
		return empty, err
	}
	return c, nil
}

type EnvOptions struct {
	ConfigFile string
}

func env(options EnvOptions) error {
	config, err := GetConfig(options.ConfigFile)
	if err != nil {
		return err
	}
	for _, v := range configToEnvVars(config) {
		fmt.Println(export(v))
	}
	return nil
}

type envVar struct {
	Name  string
	Value string
}

func export(v envVar) string {
	return "export " + v.Name + "=\"" + v.Value + "\""
}

func configToEnvVars(c config.Config) []envVar {
	return []envVar{
		{
			Name:  "GOROOT",
			Value: c.GoRoot,
		},
		{
			Name:  MiniOSRootEnv,
			Value: c.MiniOS,
		},
		{
			Name:  "PATH",
			Value: c.GoRoot + "/bin:$PATH",
		},
	}
}
<|endoftext|>


<commit_before>package env

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	_ "github.com/lib/pq"
	"github.com/mattes/migrate"
	"github.com/mattes/migrate/database/postgres"
	_ "github.com/mattes/migrate/source/file"
)

var DB *gorm.DB

func init() {
	var err error
	DB, err = gorm.Open("postgres", Config.Database)

	if err != nil {
		panic(err)
	}

	DB.LogMode(true)
}

func Migrate() {
	driver, _ := postgres.WithInstance(DB.DB(), &postgres.Config{})
	migrations, _ := migrate.NewWithDatabaseInstance("file://migrations", "postgres", driver)
	migrations.Up()
}
<commit_msg>Add Drop() and Reset() functions for database<commit_after>package env

import (
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/postgres"
	_ "github.com/lib/pq"
	"github.com/mattes/migrate"
	"github.com/mattes/migrate/database/postgres"
	_ "github.com/mattes/migrate/source/file"
)

var DB *gorm.DB

func init() {
	var err error
	DB, err = gorm.Open("postgres", Config.Database)

	if err != nil {
		panic(err)
	}

	DB.LogMode(true)
}

func Migrate() {
	driver, _ := postgres.WithInstance(DB.DB(), &postgres.Config{})
	migrations, _ := migrate.NewWithDatabaseInstance(Config.Migrations, "postgres", driver)
	migrations.Up()
}

func Drop() {
	DB.Exec(`DROP SCHEMA public CASCADE;`)
	DB.Exec(`CREATE SCHEMA public;`)
}

func Reset() {
	Drop()
	Migrate()
}
<|endoftext|>


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

package transcache_test

import (
	"encoding/json"
	"io/ioutil"
	"net"
	"sync"
	"testing"

	"encoding/gob"

	"github.com/corestoreio/csfw/storage/dbr"
	"github.com/corestoreio/csfw/storage/transcache"
	"github.com/corestoreio/csfw/storage/transcache/tcbigcache"
	"github.com/corestoreio/csfw/util/errors"
	"github.com/stretchr/testify/assert"
)

var _ transcache.Transcacher = (*transcache.Processor)(nil)

func withError() transcache.Option {
	return func(p *transcache.Processor) error {
		return errors.NewNotImplementedf("What?")
	}
}

func TestNewProcessor_NewError(t *testing.T) {
	p, err := transcache.NewProcessor(withError())
	assert.Nil(t, p)
	assert.True(t, errors.IsNotImplemented(err), "Error: %s", err)
}

func TestNewProcessor_EncoderError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}))
	if err != nil {
		t.Fatal(err)
	}

	ch := struct {
		ErrChan chan error
	}{
		ErrChan: make(chan error),
	}
	err = p.Set([]byte("key1"), ch)
	assert.True(t, errors.IsFatal(err), "Error: %s", err)
}

func TestNewProcessor_DecoderError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}), tcbigcache.With())
	if err != nil {
		t.Fatal(err)
	}
	key := []byte("key1")
	val1 := struct {
		Val string
	}{
		Val: "Gopher",
	}
	assert.NoError(t, p.Set(key, val1))

	var val2 struct {
		Val2 string
	}
	err = p.Get(key, &val2)
	assert.True(t, errors.IsFatal(err), "Error: %s", err)
}

func TestNewProcessor_GetError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}), tcbigcache.With())
	if err != nil {
		t.Fatal(err)
	}
	key := []byte("key1")
	var ch struct {
		ErrChan string
	}
	err = p.Get(key, ch)
	assert.True(t, errors.IsNotFound(err), "Error: %s", err)
}

const iterations = 30

func testCountry(t *testing.T, wg *sync.WaitGroup, p *transcache.Processor, key []byte) {
	defer wg.Done()

	var val = getTestCountry(t)

	if err := p.Set(key, val); err != nil {
		t.Fatal(err)
	}

	for i := 0; i < iterations; i++ {
		var newVal = new(Country)
		if err := p.Get(key, newVal); err != nil {
			t.Fatal(err)
		}
		assert.Exactly(t, val, newVal)
	}

	if err := p.Set(key, Country{}); err != nil {
		t.Fatal(err)
	}

	for i := 0; i < iterations; i++ {
		if err := p.Set(key, val); err != nil {
			t.Fatal(err)
		}
	}
	var newVal = new(Country)
	if err := p.Get(key, newVal); err != nil {
		t.Fatal(err)
	}
	assert.Exactly(t, val, newVal)

}

func testStoreSlice(t *testing.T, wg *sync.WaitGroup, p *transcache.Processor, key []byte) {
	defer wg.Done()

	var val = getTestStores()
	if err := p.Set(key, val); err != nil {
		t.Fatal(err)
	}
	for i := 0; i < iterations; i++ {
		var newVal TableStoreSlice
		if err := p.Get(key, &newVal); err != nil {
			t.Fatal(err)
		}
		assert.Exactly(t, val, newVal)
	}
	if err := p.Set(key, TableStoreSlice{}); err != nil {
		t.Fatal(err)
	}
	for i := 0; i < iterations; i++ {
		if err := p.Set(key, val); err != nil {
			t.Fatal(err)
		}
	}
	var newVal TableStoreSlice
	if err := p.Get(key, &newVal); err != nil {
		t.Fatal(err)
	}
	assert.Exactly(t, val, newVal)
}

func init() {
	gob.Register(&Country{})
	gob.Register(&TableStoreSlice{})
}

type Country struct {
	// IP contains the request IP address even if we run behind a proxy
	IP   net.IP `json:"ip,omitempty"`
	City struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameID  uint              `json:"geoname_id,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"city,omitempty"`
	Continent struct {
		Code      string            `json:"code,omitempty"`
		GeoNameID uint              `json:"geoname_id,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
	} `json:"continent,omitempty"`
	Country struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameID  uint              `json:"geoname_id,omitempty"`
		IsoCode    string            `json:"iso_code,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"country,omitempty"`
	Location struct {
		AccuracyRadius    int     `json:"accuracy_radius,omitempty"`
		AverageIncome     int     `json:"average_income,omitempty"`
		Latitude          float64 `json:"latitude,omitempty"`
		Longitude         float64 `json:"longitude,omitempty"`
		MetroCode         int     `json:"metro_code,omitempty"`
		PopulationDensity int     `json:"population_density,omitempty"`
		TimeZone          string  `json:"time_zone,omitempty"`
	} `json:"location,omitempty"`
	Postal struct {
		Code       string `json:"code,omitempty"`
		Confidence int    `json:"confidence,omitempty"`
	} `json:"postal,omitempty"`
	RegisteredCountry struct {
		GeoNameID uint              `json:"geoname_id,omitempty"`
		IsoCode   string            `json:"iso_code,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
	} `json:"registered_country,omitempty"`
	RepresentedCountry struct {
		GeoNameID uint              `json:"geoname_id,omitempty"`
		IsoCode   string            `json:"iso_code,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
		Type      string            `json:"type,omitempty"`
	} `json:"represented_country,omitempty"`
	Subdivision []struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameId  uint              `json:"geoname_id,omitempty"`
		IsoCode    string            `json:"iso_code,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"subdivisions,omitempty"`
	Traits struct {
		AutonomousSystemNumber       int    `json:"autonomous_system_number,omitempty"`
		AutonomousSystemOrganization string `json:"autonomous_system_organization,omitempty"`
		Domain                       string `json:"domain,omitempty"`
		IsAnonymousProxy             bool   `json:"is_anonymous_proxy,omitempty"`
		IsSatelliteProvider          bool   `json:"is_satellite_provider,omitempty"`
		Isp                          string `json:"isp,omitempty"`
		IpAddress                    string `json:"ip_address,omitempty"`
		Organization                 string `json:"organization,omitempty"`
		UserType                     string `json:"user_type,omitempty"`
	} `json:"traits,omitempty"`
	MaxMind struct {
		QueriesRemaining int `json:"queries_remaining,omitempty"`
	} `json:"maxmind,omitempty"`
}

func getTestCountry(t interface {
	Fatal(...interface{})
}) *Country {
	td, err := ioutil.ReadFile("testdata/response.json")
	if err != nil {
		t.Fatal(err)
	}
	c := new(Country)
	if err := json.Unmarshal(td, c); err != nil {
		t.Fatal(err)
	}
	return c
}

// TableStoreSlice represents a collection type for DB table store
// Generated via tableToStruct.
type TableStoreSlice []*TableStore

// TableStore represents a type for DB table store
// Generated via tableToStruct.
type TableStore struct {
	StoreID   int64          `db:"store_id" json:",omitempty"`   // store_id smallint(5) unsigned NOT NULL PRI  auto_increment
	Code      dbr.NullString `db:"code" json:",omitempty"`       // code varchar(32) NULL UNI
	WebsiteID int64          `db:"website_id" json:",omitempty"` // website_id smallint(5) unsigned NOT NULL MUL DEFAULT '0'
	GroupID   int64          `db:"group_id" json:",omitempty"`   // group_id smallint(5) unsigned NOT NULL MUL DEFAULT '0'
	Name      string         `db:"name" json:",omitempty"`       // name varchar(255) NOT NULL
	SortOrder int64          `db:"sort_order" json:",omitempty"` // sort_order smallint(5) unsigned NOT NULL  DEFAULT '0'
	IsActive  bool           `db:"is_active" json:",omitempty"`  // is_active smallint(5) unsigned NOT NULL MUL DEFAULT '0'
}

func getTestStores() TableStoreSlice {
	return TableStoreSlice{
		&TableStore{StoreID: 0, Code: dbr.NewNullString("admin"), WebsiteID: 0, GroupID: 0, Name: "Admin", SortOrder: 0, IsActive: true},
		&TableStore{StoreID: 5, Code: dbr.NewNullString("au"), WebsiteID: 2, GroupID: 3, Name: "Australia", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 1, Code: dbr.NewNullString("de"), WebsiteID: 1, GroupID: 1, Name: "Germany", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 4, Code: dbr.NewNullString("uk"), WebsiteID: 1, GroupID: 2, Name: "UK", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 2, Code: dbr.NewNullString("at"), WebsiteID: 1, GroupID: 1, Name: "Österreich", SortOrder: 20, IsActive: true},
		&TableStore{StoreID: 6, Code: dbr.NewNullString("nz"), WebsiteID: 2, GroupID: 3, Name: "Kiwi", SortOrder: 30, IsActive: true},
		&TableStore{IsActive: false, StoreID: 3, Code: dbr.NewNullString("ch"), WebsiteID: 1, GroupID: 1, Name: "Schweiz", SortOrder: 30},
	}
}
<commit_msg>storage/transcache: Update package for null DB types<commit_after>// Copyright 2015-2016, Cyrill @ Schumacher.fm and the CoreStore contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package transcache_test

import (
	"encoding/gob"
	"encoding/json"
	"io/ioutil"
	"net"
	"sync"
	"testing"

	"github.com/corestoreio/csfw/storage/transcache"
	"github.com/corestoreio/csfw/storage/transcache/tcbigcache"
	"github.com/corestoreio/csfw/util/errors"
	"github.com/corestoreio/csfw/util/null"
	"github.com/stretchr/testify/assert"
)

var _ transcache.Transcacher = (*transcache.Processor)(nil)

func withError() transcache.Option {
	return func(p *transcache.Processor) error {
		return errors.NewNotImplementedf("What?")
	}
}

func TestNewProcessor_NewError(t *testing.T) {
	p, err := transcache.NewProcessor(withError())
	assert.Nil(t, p)
	assert.True(t, errors.IsNotImplemented(err), "Error: %s", err)
}

func TestNewProcessor_EncoderError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}))
	if err != nil {
		t.Fatal(err)
	}

	ch := struct {
		ErrChan chan error
	}{
		ErrChan: make(chan error),
	}
	err = p.Set([]byte("key1"), ch)
	assert.True(t, errors.IsFatal(err), "Error: %s", err)
}

func TestNewProcessor_DecoderError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}), tcbigcache.With())
	if err != nil {
		t.Fatal(err)
	}
	key := []byte("key1")
	val1 := struct {
		Val string
	}{
		Val: "Gopher",
	}
	assert.NoError(t, p.Set(key, val1))

	var val2 struct {
		Val2 string
	}
	err = p.Get(key, &val2)
	assert.True(t, errors.IsFatal(err), "Error: %s", err)
}

func TestNewProcessor_GetError(t *testing.T) {
	p, err := transcache.NewProcessor(transcache.WithPooledEncoder(transcache.GobCodec{}), tcbigcache.With())
	if err != nil {
		t.Fatal(err)
	}
	key := []byte("key1")
	var ch struct {
		ErrChan string
	}
	err = p.Get(key, ch)
	assert.True(t, errors.IsNotFound(err), "Error: %s", err)
}

const iterations = 30

func testCountry(t *testing.T, wg *sync.WaitGroup, p *transcache.Processor, key []byte) {
	defer wg.Done()

	var val = getTestCountry(t)

	if err := p.Set(key, val); err != nil {
		t.Fatal(err)
	}

	for i := 0; i < iterations; i++ {
		var newVal = new(Country)
		if err := p.Get(key, newVal); err != nil {
			t.Fatal(err)
		}
		assert.Exactly(t, val, newVal)
	}

	if err := p.Set(key, Country{}); err != nil {
		t.Fatal(err)
	}

	for i := 0; i < iterations; i++ {
		if err := p.Set(key, val); err != nil {
			t.Fatal(err)
		}
	}
	var newVal = new(Country)
	if err := p.Get(key, newVal); err != nil {
		t.Fatal(err)
	}
	assert.Exactly(t, val, newVal)

}

func testStoreSlice(t *testing.T, wg *sync.WaitGroup, p *transcache.Processor, key []byte) {
	defer wg.Done()

	var val = getTestStores()
	if err := p.Set(key, val); err != nil {
		t.Fatal(err)
	}
	for i := 0; i < iterations; i++ {
		var newVal TableStoreSlice
		if err := p.Get(key, &newVal); err != nil {
			t.Fatal(err)
		}
		assert.Exactly(t, val, newVal)
	}
	if err := p.Set(key, TableStoreSlice{}); err != nil {
		t.Fatal(err)
	}
	for i := 0; i < iterations; i++ {
		if err := p.Set(key, val); err != nil {
			t.Fatal(err)
		}
	}
	var newVal TableStoreSlice
	if err := p.Get(key, &newVal); err != nil {
		t.Fatal(err)
	}
	assert.Exactly(t, val, newVal)
}

func init() {
	gob.Register(&Country{})
	gob.Register(&TableStoreSlice{})
}

type Country struct {
	// IP contains the request IP address even if we run behind a proxy
	IP   net.IP `json:"ip,omitempty"`
	City struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameID  uint              `json:"geoname_id,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"city,omitempty"`
	Continent struct {
		Code      string            `json:"code,omitempty"`
		GeoNameID uint              `json:"geoname_id,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
	} `json:"continent,omitempty"`
	Country struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameID  uint              `json:"geoname_id,omitempty"`
		IsoCode    string            `json:"iso_code,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"country,omitempty"`
	Location struct {
		AccuracyRadius    int     `json:"accuracy_radius,omitempty"`
		AverageIncome     int     `json:"average_income,omitempty"`
		Latitude          float64 `json:"latitude,omitempty"`
		Longitude         float64 `json:"longitude,omitempty"`
		MetroCode         int     `json:"metro_code,omitempty"`
		PopulationDensity int     `json:"population_density,omitempty"`
		TimeZone          string  `json:"time_zone,omitempty"`
	} `json:"location,omitempty"`
	Postal struct {
		Code       string `json:"code,omitempty"`
		Confidence int    `json:"confidence,omitempty"`
	} `json:"postal,omitempty"`
	RegisteredCountry struct {
		GeoNameID uint              `json:"geoname_id,omitempty"`
		IsoCode   string            `json:"iso_code,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
	} `json:"registered_country,omitempty"`
	RepresentedCountry struct {
		GeoNameID uint              `json:"geoname_id,omitempty"`
		IsoCode   string            `json:"iso_code,omitempty"`
		Names     map[string]string `json:"names,omitempty"`
		Type      string            `json:"type,omitempty"`
	} `json:"represented_country,omitempty"`
	Subdivision []struct {
		Confidence int               `json:"confidence,omitempty"`
		GeoNameId  uint              `json:"geoname_id,omitempty"`
		IsoCode    string            `json:"iso_code,omitempty"`
		Names      map[string]string `json:"names,omitempty"`
	} `json:"subdivisions,omitempty"`
	Traits struct {
		AutonomousSystemNumber       int    `json:"autonomous_system_number,omitempty"`
		AutonomousSystemOrganization string `json:"autonomous_system_organization,omitempty"`
		Domain                       string `json:"domain,omitempty"`
		IsAnonymousProxy             bool   `json:"is_anonymous_proxy,omitempty"`
		IsSatelliteProvider          bool   `json:"is_satellite_provider,omitempty"`
		Isp                          string `json:"isp,omitempty"`
		IpAddress                    string `json:"ip_address,omitempty"`
		Organization                 string `json:"organization,omitempty"`
		UserType                     string `json:"user_type,omitempty"`
	} `json:"traits,omitempty"`
	MaxMind struct {
		QueriesRemaining int `json:"queries_remaining,omitempty"`
	} `json:"maxmind,omitempty"`
}

func getTestCountry(t interface {
	Fatal(...interface{})
}) *Country {
	td, err := ioutil.ReadFile("testdata/response.json")
	if err != nil {
		t.Fatal(err)
	}
	c := new(Country)
	if err := json.Unmarshal(td, c); err != nil {
		t.Fatal(err)
	}
	return c
}

// TableStoreSlice represents a collection type for DB table store
// Generated via tableToStruct.
type TableStoreSlice []*TableStore

// TableStore represents a type for DB table store
// Generated via tableToStruct.
type TableStore struct {
	StoreID   int64       `db:"store_id" json:",omitempty"`   // store_id smallint(5) unsigned NOT NULL PRI  auto_increment
	Code      null.String `db:"code" json:",omitempty"`       // code varchar(32) NULL UNI
	WebsiteID int64       `db:"website_id" json:",omitempty"` // website_id smallint(5) unsigned NOT NULL MUL DEFAULT '0'
	GroupID   int64       `db:"group_id" json:",omitempty"`   // group_id smallint(5) unsigned NOT NULL MUL DEFAULT '0'
	Name      string      `db:"name" json:",omitempty"`       // name varchar(255) NOT NULL
	SortOrder int64       `db:"sort_order" json:",omitempty"` // sort_order smallint(5) unsigned NOT NULL  DEFAULT '0'
	IsActive  bool        `db:"is_active" json:",omitempty"`  // is_active smallint(5) unsigned NOT NULL MUL DEFAULT '0'
}

func getTestStores() TableStoreSlice {
	return TableStoreSlice{
		&TableStore{StoreID: 0, Code: null.StringFrom("admin"), WebsiteID: 0, GroupID: 0, Name: "Admin", SortOrder: 0, IsActive: true},
		&TableStore{StoreID: 5, Code: null.StringFrom("au"), WebsiteID: 2, GroupID: 3, Name: "Australia", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 1, Code: null.StringFrom("de"), WebsiteID: 1, GroupID: 1, Name: "Germany", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 4, Code: null.StringFrom("uk"), WebsiteID: 1, GroupID: 2, Name: "UK", SortOrder: 10, IsActive: true},
		&TableStore{StoreID: 2, Code: null.StringFrom("at"), WebsiteID: 1, GroupID: 1, Name: "Österreich", SortOrder: 20, IsActive: true},
		&TableStore{StoreID: 6, Code: null.StringFrom("nz"), WebsiteID: 2, GroupID: 3, Name: "Kiwi", SortOrder: 30, IsActive: true},
		&TableStore{IsActive: false, StoreID: 3, Code: null.StringFrom("ch"), WebsiteID: 1, GroupID: 1, Name: "Schweiz", SortOrder: 30},
	}
}
<|endoftext|>


<commit_before>package client

import (
	"errors"
	"strings"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/commands"
	"github.com/emersion/go-imap/responses"
)

var ErrNoMailboxSelected = errors.New("No mailbox selected")

// Requests a checkpoint of the currently selected mailbox. A checkpoint refers
// to any implementation-dependent housekeeping associated with the mailbox that
// is not normally executed as part of each command.
func (c *Client) Check() (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Check{}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Permanently removes all messages that have the \Deleted flag set from the
// currently selected mailbox, and returns to the authenticated state from the
// selected state.
func (c *Client) Close() (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Close{}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	if err != nil {
		return
	}

	c.State = imap.AuthenticatedState
	c.Mailbox = nil
	return
}

// Permanently removes all messages that have the \Deleted flag set from the
// currently selected mailbox.
// If ch is not nil, sends sequence IDs of each deleted message to this channel.
func (c *Client) Expunge(ch chan uint32) (err error) {
	defer close(ch)

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Expunge{}

	var res *responses.Expunge
	if ch != nil {
		res = &responses.Expunge{SeqNums: ch}
	}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

func (c *Client) search(uid bool, criteria *imap.SearchCriteria) (ids []uint32, err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Search{
		Charset:  "UTF-8",
		Criteria: criteria,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	res := &responses.Search{}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	ids = res.Ids
	return
}

// Searches the mailbox for messages that match the given searching criteria.
// Searching criteria consist of one or more search keys. The response contains
// a list of message sequence IDs corresponding to those messages that match the
// searching criteria.
// When multiple keys are specified, the result is the intersection (AND
// function) of all the messages that match those keys.
// Criteria must be UTF-8 encoded.
// See RFC 3501 section 6.4.4 for a list of searching criteria.
func (c *Client) Search(criteria *imap.SearchCriteria) (seqNums []uint32, err error) {
	return c.search(false, criteria)
}

// Identical to Search, but unique identifiers are returned instead of message
// sequence numbers.
func (c *Client) UidSearch(criteria *imap.SearchCriteria) (uids []uint32, err error) {
	return c.search(true, criteria)
}

func (c *Client) fetch(uid bool, seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	defer close(ch)

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Fetch{
		SeqSet: seqset,
		Items:  items,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	res := &responses.Fetch{Messages: ch}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Retrieves data associated with a message in the mailbox.
// See RFC 3501 section 6.4.5 for a list of items that can be requested.
func (c *Client) Fetch(seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	return c.fetch(false, seqset, items, ch)
}

// Identical to Fetch, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidFetch(seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	return c.fetch(true, seqset, items, ch)
}

func (c *Client) store(uid bool, seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	defer (func() {
		if ch != nil {
			close(ch)
		}
	})()

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	// If ch is nil, the updated values are data which will be lost, so don't
	// retrieve it.
	if ch == nil && !strings.HasSuffix(item, imap.SilentOp) {
		item += imap.SilentOp
	}

	var cmd imap.Commander
	cmd = &commands.Store{
		SeqSet: seqset,
		Item:   item,
		Value:  value,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	var res *responses.Fetch
	if ch != nil {
		res = &responses.Fetch{Messages: ch}
	}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Alters data associated with a message in the mailbox. If ch is not nil, the
// updated value of the data will be sent to this channel.
// See RFC 3501 section 6.4.6 for a list of items that can be updated.
func (c *Client) Store(seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	return c.store(false, seqset, item, value, ch)
}

// Identical to Store, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidStore(seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	return c.store(true, seqset, item, value, ch)
}

func (c *Client) copy(uid bool, seqset *imap.SeqSet, dest string) (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Copy{
		SeqSet:  seqset,
		Mailbox: dest,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Copies the specified message(s) to the end of the specified destination
// mailbox.
func (c *Client) Copy(seqset *imap.SeqSet, dest string) (err error) {
	return c.copy(false, seqset, dest)
}

// Identical to Copy, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidCopy(seqset *imap.SeqSet, dest string) (err error) {
	return c.copy(true, seqset, dest)
}
<commit_msg>When searching fall back to US-ASCII if BADCHARSET is received.<commit_after>package client

import (
	"errors"
	"strings"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/commands"
	"github.com/emersion/go-imap/responses"
)

var ErrNoMailboxSelected = errors.New("No mailbox selected")

// Requests a checkpoint of the currently selected mailbox. A checkpoint refers
// to any implementation-dependent housekeeping associated with the mailbox that
// is not normally executed as part of each command.
func (c *Client) Check() (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Check{}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Permanently removes all messages that have the \Deleted flag set from the
// currently selected mailbox, and returns to the authenticated state from the
// selected state.
func (c *Client) Close() (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Close{}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	if err != nil {
		return
	}

	c.State = imap.AuthenticatedState
	c.Mailbox = nil
	return
}

// Permanently removes all messages that have the \Deleted flag set from the
// currently selected mailbox.
// If ch is not nil, sends sequence IDs of each deleted message to this channel.
func (c *Client) Expunge(ch chan uint32) (err error) {
	defer close(ch)

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	cmd := &commands.Expunge{}

	var res *responses.Expunge
	if ch != nil {
		res = &responses.Expunge{SeqNums: ch}
	}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

func (c *Client) search(uid bool, criteria *imap.SearchCriteria) (ids []uint32, err error) {
	ids, status, err := c.executeSearch(uid, criteria, "UTF-8")
	if status != nil && status.Code == imap.CodeBadCharset {
		ids, _, err = c.executeSearch(uid, criteria, "US-ASCII")
		return
	}

	return ids, err
}

func (c *Client) executeSearch(uid bool, criteria *imap.SearchCriteria, charset string) (ids []uint32, status *imap.StatusResp, err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Search{
		Charset:  charset,
		Criteria: criteria,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	res := &responses.Search{}

	status, err = c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	ids = res.Ids

	return
}

// Searches the mailbox for messages that match the given searching criteria.
// Searching criteria consist of one or more search keys. The response contains
// a list of message sequence IDs corresponding to those messages that match the
// searching criteria.
// When multiple keys are specified, the result is the intersection (AND
// function) of all the messages that match those keys.
// Criteria must be UTF-8 encoded.
// See RFC 3501 section 6.4.4 for a list of searching criteria.
func (c *Client) Search(criteria *imap.SearchCriteria) (seqNums []uint32, err error) {
	return c.search(false, criteria)
}

// Identical to Search, but unique identifiers are returned instead of message
// sequence numbers.
func (c *Client) UidSearch(criteria *imap.SearchCriteria) (uids []uint32, err error) {
	return c.search(true, criteria)
}

func (c *Client) fetch(uid bool, seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	defer close(ch)

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Fetch{
		SeqSet: seqset,
		Items:  items,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	res := &responses.Fetch{Messages: ch}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Retrieves data associated with a message in the mailbox.
// See RFC 3501 section 6.4.5 for a list of items that can be requested.
func (c *Client) Fetch(seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	return c.fetch(false, seqset, items, ch)
}

// Identical to Fetch, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidFetch(seqset *imap.SeqSet, items []string, ch chan *imap.Message) (err error) {
	return c.fetch(true, seqset, items, ch)
}

func (c *Client) store(uid bool, seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	defer (func() {
		if ch != nil {
			close(ch)
		}
	})()

	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	// If ch is nil, the updated values are data which will be lost, so don't
	// retrieve it.
	if ch == nil && !strings.HasSuffix(item, imap.SilentOp) {
		item += imap.SilentOp
	}

	var cmd imap.Commander
	cmd = &commands.Store{
		SeqSet: seqset,
		Item:   item,
		Value:  value,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	var res *responses.Fetch
	if ch != nil {
		res = &responses.Fetch{Messages: ch}
	}

	status, err := c.execute(cmd, res)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Alters data associated with a message in the mailbox. If ch is not nil, the
// updated value of the data will be sent to this channel.
// See RFC 3501 section 6.4.6 for a list of items that can be updated.
func (c *Client) Store(seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	return c.store(false, seqset, item, value, ch)
}

// Identical to Store, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidStore(seqset *imap.SeqSet, item string, value interface{}, ch chan *imap.Message) (err error) {
	return c.store(true, seqset, item, value, ch)
}

func (c *Client) copy(uid bool, seqset *imap.SeqSet, dest string) (err error) {
	if c.State != imap.SelectedState {
		err = ErrNoMailboxSelected
		return
	}

	var cmd imap.Commander
	cmd = &commands.Copy{
		SeqSet:  seqset,
		Mailbox: dest,
	}
	if uid {
		cmd = &commands.Uid{Cmd: cmd}
	}

	status, err := c.execute(cmd, nil)
	if err != nil {
		return
	}

	err = status.Err()
	return
}

// Copies the specified message(s) to the end of the specified destination
// mailbox.
func (c *Client) Copy(seqset *imap.SeqSet, dest string) (err error) {
	return c.copy(false, seqset, dest)
}

// Identical to Copy, but seqset is interpreted as containing unique
// identifiers instead of message sequence numbers.
func (c *Client) UidCopy(seqset *imap.SeqSet, dest string) (err error) {
	return c.copy(true, seqset, dest)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

import (
	"bufio"
	"fmt"
	"io"
	"regexp"
	"unicode/utf8"
)

func parse(r io.Reader, name string) (prog, error) {
	p := &parser{
		r:    bufio.NewReader(r),
		name: name,
		npos: position{
			line: 1,
			col:  1,
		},
	}
	p.push(&p.prog.stmts)
	p.next()
	p.program()
	return p.prog, p.err
}

type parser struct {
	r    *bufio.Reader
	name string

	err error

	ltok token
	tok  token
	lval string
	val  string

	lpos position
	pos  position
	npos position

	prog  prog
	stack []interface{}
}

type position struct {
	line int
	col  int
}

var reserved = map[rune]bool{
	'\n': true,
	'#':  true,
	'&':  true,
	'>':  true,
	'<':  true,
	'|':  true,
	';':  true,
	'(':  true,
	')':  true,
}

// like reserved, but these can appear in the middle of a word
var starters = map[rune]bool{
	'{': true,
	'}': true,
}

var space = map[rune]bool{
	' ':  true,
	'\t': true,
}

var identRe = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)

func (p *parser) readRune() (rune, error) {
	r, _, err := p.r.ReadRune()
	if err != nil {
		if err == io.EOF {
			p.eof()
		} else {
			p.errPass(err)
		}
		return 0, err
	}
	if r == '\n' {
		p.npos.line++
		p.npos.col = 1
	} else {
		p.npos.col++
	}
	return r, nil
}

func (p *parser) unreadRune() {
	p.npos.col--
	if err := p.r.UnreadRune(); err != nil {
		panic(err)
	}
}

func (p *parser) readOnly(wanted rune) bool {
	r, err := p.readRune()
	if r == wanted {
		return true
	}
	if err == nil {
		p.unreadRune()
	}
	return false
}

func (p *parser) next() {
	p.lpos = p.pos
	r := ' '
	var err error
	for space[r] {
		r, err = p.readRune()
		if err != nil {
			return
		}
	}
	p.pos = p.npos
	p.pos.col--
	if r == '\\' && p.readOnly('\n') {
		p.next()
		return
	}
	if reserved[r] || starters[r] {
		p.lval = p.val
		switch r {
		case '#':
			p.advance(COMMENT, p.readUpTo('\n'))
		case '\n':
			p.advance('\n', "")
		default:
			p.setTok(p.doToken(r))
		}
		return
	}
	p.lval = p.val
	rs := []rune{r}
	q := rune(0)
	if r == '"' || r == '\'' {
		q = r
	}
	for {
		r, err = p.readRune()
		if err != nil {
			if q != 0 {
				p.errWanted(token(q))
			}
			break
		}
		if q != 0 {
			if q == '"' && r == '\\' {
				rs = append(rs, r)
				r, _ = p.readRune()
			} else if r == q {
				q = 0
			}
		} else if r == '"' || r == '\'' {
			q = r
		} else if reserved[r] || space[r] {
			p.unreadRune()
			break
		}
		rs = append(rs, r)
	}
	p.setTok(WORD)
	p.val = string(rs)
}

func (p *parser) doToken(r rune) token {
	switch r {
	case '&':
		if p.readOnly('&') {
			return LAND
		}
		return AND
	case '|':
		if p.readOnly('|') {
			return LOR
		}
		return OR
	case '(':
		return LPAREN
	case '{':
		return LBRACE
	case ')':
		return RPAREN
	case '}':
		return RBRACE
	case ';':
		if p.readOnly(';') {
			return DSEMICOLON
		}
		return SEMICOLON
	case '<':
		return LSS
	case '>':
		if p.readOnly('>') {
			return SHR
		}
		return GTR
	default:
		return token(r)
	}
}

func (p *parser) advance(tok token, val string) {
	p.setTok(tok)
	p.setVal(val)
}

func (p *parser) setTok(tok token) {
	p.ltok = p.tok
	p.tok = tok
}

func (p *parser) setVal(val string) {
	p.lval = p.val
	p.val = val
}

func (p *parser) eof() {
	p.advance(EOF, "EOF")
}

func (p *parser) readUpTo(delim byte) string {
	b, err := p.r.ReadBytes(delim)
	cont := b
	if err == io.EOF {
	} else if err != nil {
		p.errPass(err)
	} else {
		cont = cont[:len(b)-1]
	}
	p.npos.col += utf8.RuneCount(b)
	return string(cont)
}

// We can't simply have these as tokens as they can sometimes be valid
// words, e.g. `echo if`.
var reservedWords = map[token]string{
	IF:    "if",
	THEN:  "then",
	ELIF:  "elif",
	ELSE:  "else",
	FI:    "fi",
	WHILE: "while",
	DO:    "do",
	DONE:  "done",
}

func (p *parser) peek(tok token) bool {
	return p.tok == tok || (p.tok == WORD && p.val == reservedWords[tok])
}

func (p *parser) got(tok token) bool {
	if p.peek(tok) {
		p.next()
		return true
	}
	return false
}

func (p *parser) want(tok token) {
	if !p.peek(tok) {
		p.errWanted(tok)
		return
	}
	p.next()
}

func (p *parser) errPass(err error) {
	if p.err == nil {
		p.err = err
	}
	p.eof()
}

func (p *parser) posErr(pos position, format string, v ...interface{}) {
	if p.err != nil {
		return
	}
	prefix := fmt.Sprintf("%s:%d:%d: ", p.name, pos.line, pos.col)
	p.errPass(fmt.Errorf(prefix+format, v...))
}

func (p *parser) curErr(format string, v ...interface{}) {
	p.posErr(p.pos, format, v...)
}

func (p *parser) errWantedStr(s string) {
	if p.tok == EOF {
		p.pos = p.npos
	}
	p.curErr("unexpected token %s - wanted %s", p.tok, s)
}

func (p *parser) errWanted(tok token) {
	p.errWantedStr(tok.String())
}

func (p *parser) errAfterStr(s string) {
	p.curErr("unexpected token %s after %s", p.tok, s)
}

func (p *parser) add(n node) {
	cur := p.stack[len(p.stack)-1]
	switch x := cur.(type) {
	case *[]node:
		*x = append(*x, n)
	case *node:
		if *x != nil {
			panic("single node set twice")
		}
		*x = n
	default:
		panic("unknown type in the stack")
	}
}

func (p *parser) pop() {
	p.stack = p.stack[:len(p.stack)-1]
}

func (p *parser) push(v interface{}) {
	p.stack = append(p.stack, v)
}

func (p *parser) popAdd(n node) {
	p.pop()
	p.add(n)
}

func (p *parser) program() {
	for p.tok != EOF {
		p.command()
	}
}

func (p *parser) commands(stop ...token) (count int) {
	for p.tok != EOF {
		for _, tok := range stop {
			if p.peek(tok) {
				return
			}
		}
		p.command()
		count++
	}
	return
}

func (p *parser) command() {
	switch {
	case p.got(COMMENT):
		com := comment{
			text: p.lval,
		}
		p.add(com)
	case p.got('\n'), p.got(COMMENT):
		if p.tok != EOF {
			p.command()
		}
	case p.got(LPAREN):
		var sub subshell
		p.push(&sub.stmts)
		if p.commands(RPAREN) == 0 {
			p.errWantedStr("command")
		}
		p.want(RPAREN)
		p.popAdd(sub)
	case p.got(LBRACE):
		var bl block
		p.push(&bl.stmts)
		if p.commands(RBRACE) == 0 {
			p.errWantedStr("command")
		}
		p.want(RBRACE)
		p.popAdd(bl)
	case p.got(IF):
		var ifs ifStmt
		p.push(&ifs.cond)
		p.command()
		p.pop()
		p.want(THEN)
		p.push(&ifs.thenStmts)
		p.commands(FI, ELIF, ELSE)
		p.pop()
		p.push(&ifs.elifs)
		for p.got(ELIF) {
			var elf elif
			p.push(&elf.cond)
			p.command()
			p.pop()
			p.want(THEN)
			p.push(&elf.thenStmts)
			p.commands(FI, ELIF, ELSE)
			p.popAdd(elf)
		}
		if p.got(ELSE) {
			p.pop()
			p.push(&ifs.elseStmts)
			p.commands(FI)
		}
		p.want(FI)
		p.popAdd(ifs)
	case p.got(WHILE):
		var whl whileStmt
		p.push(&whl.cond)
		p.command()
		p.pop()
		p.want(DO)
		p.push(&whl.doStmts)
		p.commands(DONE)
		p.want(DONE)
		p.popAdd(whl)
	case p.got(WORD):
		var cmd command
		p.push(&cmd.args)
		p.add(lit{val: p.lval})
		first := p.lpos
	args:
		for p.tok != EOF {
			switch {
			case p.got(WORD):
				p.add(lit{val: p.lval})
			case p.got(AND):
				cmd.background = true
				break args
			case p.got(LAND):
				p.binaryExpr(LAND, cmd)
				return
			case p.got(OR):
				p.binaryExpr(OR, cmd)
				return
			case p.got(LOR):
				p.binaryExpr(LOR, cmd)
				return
			case p.got(LPAREN):
				if !identRe.MatchString(p.lval) {
					p.posErr(first, "invalid func name %q", p.lval)
					break args
				}
				fun := funcDecl{
					name: lit{val: p.lval},
				}
				p.want(RPAREN)
				p.push(&fun.body)
				p.command()
				p.pop()
				p.popAdd(fun)
				return
			case p.gotRedirect():
			case p.got(SEMICOLON):
				break args
			case p.got('\n'):
				break args
			default:
				p.errAfterStr("command")
			}
		}
		p.popAdd(cmd)
	default:
		p.errWantedStr("command")
	}
}

func (p *parser) binaryExpr(op token, left node) {
	b := binaryExpr{op: op}
	p.push(&b.Y)
	p.command()
	p.pop()
	b.X = left
	p.popAdd(b)
}

func (p *parser) gotRedirect() bool {
	var r redirect
	switch {
	case p.got(GTR):
		r.op = GTR
		if p.got(AND) {
			p.want(WORD)
			r.obj = lit{val: "&" + p.lval}
		} else {
			p.want(WORD)
			r.obj = lit{val: p.lval}
		}
	case p.got(SHR):
		r.op = SHR
		p.want(WORD)
		r.obj = lit{val: p.lval}
	case p.got(LSS):
		r.op = LSS
		p.want(WORD)
		r.obj = lit{val: p.lval}
	default:
		return false
	}
	p.add(r)
	return true
}
<commit_msg>Simplify value assignment<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

import (
	"bufio"
	"fmt"
	"io"
	"regexp"
	"unicode/utf8"
)

func parse(r io.Reader, name string) (prog, error) {
	p := &parser{
		r:    bufio.NewReader(r),
		name: name,
		npos: position{
			line: 1,
			col:  1,
		},
	}
	p.push(&p.prog.stmts)
	p.next()
	p.program()
	return p.prog, p.err
}

type parser struct {
	r    *bufio.Reader
	name string

	err error

	ltok token
	tok  token
	lval string
	val  string

	lpos position
	pos  position
	npos position

	prog  prog
	stack []interface{}
}

type position struct {
	line int
	col  int
}

var reserved = map[rune]bool{
	'\n': true,
	'#':  true,
	'&':  true,
	'>':  true,
	'<':  true,
	'|':  true,
	';':  true,
	'(':  true,
	')':  true,
}

// like reserved, but these can appear in the middle of a word
var starters = map[rune]bool{
	'{': true,
	'}': true,
}

var space = map[rune]bool{
	' ':  true,
	'\t': true,
}

var identRe = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)

func (p *parser) readRune() (rune, error) {
	r, _, err := p.r.ReadRune()
	if err != nil {
		if err == io.EOF {
			p.eof()
		} else {
			p.errPass(err)
		}
		return 0, err
	}
	if r == '\n' {
		p.npos.line++
		p.npos.col = 1
	} else {
		p.npos.col++
	}
	return r, nil
}

func (p *parser) unreadRune() {
	p.npos.col--
	if err := p.r.UnreadRune(); err != nil {
		panic(err)
	}
}

func (p *parser) readOnly(wanted rune) bool {
	r, err := p.readRune()
	if r == wanted {
		return true
	}
	if err == nil {
		p.unreadRune()
	}
	return false
}

func (p *parser) next() {
	p.lpos = p.pos
	r := ' '
	var err error
	for space[r] {
		r, err = p.readRune()
		if err != nil {
			return
		}
	}
	p.pos = p.npos
	p.pos.col--
	if r == '\\' && p.readOnly('\n') {
		p.next()
		return
	}
	p.lval = p.val
	if reserved[r] || starters[r] {
		switch r {
		case '#':
			p.advance(COMMENT, p.readUpTo('\n'))
		case '\n':
			p.advance('\n', "")
		default:
			p.setTok(p.doToken(r))
		}
		return
	}
	rs := []rune{r}
	q := rune(0)
	if r == '"' || r == '\'' {
		q = r
	}
	for {
		r, err = p.readRune()
		if err != nil {
			if q != 0 {
				p.errWanted(token(q))
			}
			break
		}
		if q != 0 {
			if q == '"' && r == '\\' {
				rs = append(rs, r)
				r, _ = p.readRune()
			} else if r == q {
				q = 0
			}
		} else if r == '"' || r == '\'' {
			q = r
		} else if reserved[r] || space[r] {
			p.unreadRune()
			break
		}
		rs = append(rs, r)
	}
	p.setTok(WORD)
	p.val = string(rs)
}

func (p *parser) doToken(r rune) token {
	switch r {
	case '&':
		if p.readOnly('&') {
			return LAND
		}
		return AND
	case '|':
		if p.readOnly('|') {
			return LOR
		}
		return OR
	case '(':
		return LPAREN
	case '{':
		return LBRACE
	case ')':
		return RPAREN
	case '}':
		return RBRACE
	case ';':
		if p.readOnly(';') {
			return DSEMICOLON
		}
		return SEMICOLON
	case '<':
		return LSS
	case '>':
		if p.readOnly('>') {
			return SHR
		}
		return GTR
	default:
		return token(r)
	}
}

func (p *parser) advance(tok token, val string) {
	p.setTok(tok)
	p.lval = p.val
	p.val = val
}

func (p *parser) setTok(tok token) {
	p.ltok = p.tok
	p.tok = tok
}

func (p *parser) eof() {
	p.advance(EOF, "EOF")
}

func (p *parser) readUpTo(delim byte) string {
	b, err := p.r.ReadBytes(delim)
	cont := b
	if err == io.EOF {
	} else if err != nil {
		p.errPass(err)
	} else {
		cont = cont[:len(b)-1]
	}
	p.npos.col += utf8.RuneCount(b)
	return string(cont)
}

// We can't simply have these as tokens as they can sometimes be valid
// words, e.g. `echo if`.
var reservedWords = map[token]string{
	IF:    "if",
	THEN:  "then",
	ELIF:  "elif",
	ELSE:  "else",
	FI:    "fi",
	WHILE: "while",
	DO:    "do",
	DONE:  "done",
}

func (p *parser) peek(tok token) bool {
	return p.tok == tok || (p.tok == WORD && p.val == reservedWords[tok])
}

func (p *parser) got(tok token) bool {
	if p.peek(tok) {
		p.next()
		return true
	}
	return false
}

func (p *parser) want(tok token) {
	if !p.peek(tok) {
		p.errWanted(tok)
		return
	}
	p.next()
}

func (p *parser) errPass(err error) {
	if p.err == nil {
		p.err = err
	}
	p.eof()
}

func (p *parser) posErr(pos position, format string, v ...interface{}) {
	if p.err != nil {
		return
	}
	prefix := fmt.Sprintf("%s:%d:%d: ", p.name, pos.line, pos.col)
	p.errPass(fmt.Errorf(prefix+format, v...))
}

func (p *parser) curErr(format string, v ...interface{}) {
	p.posErr(p.pos, format, v...)
}

func (p *parser) errWantedStr(s string) {
	if p.tok == EOF {
		p.pos = p.npos
	}
	p.curErr("unexpected token %s - wanted %s", p.tok, s)
}

func (p *parser) errWanted(tok token) {
	p.errWantedStr(tok.String())
}

func (p *parser) errAfterStr(s string) {
	p.curErr("unexpected token %s after %s", p.tok, s)
}

func (p *parser) add(n node) {
	cur := p.stack[len(p.stack)-1]
	switch x := cur.(type) {
	case *[]node:
		*x = append(*x, n)
	case *node:
		if *x != nil {
			panic("single node set twice")
		}
		*x = n
	default:
		panic("unknown type in the stack")
	}
}

func (p *parser) pop() {
	p.stack = p.stack[:len(p.stack)-1]
}

func (p *parser) push(v interface{}) {
	p.stack = append(p.stack, v)
}

func (p *parser) popAdd(n node) {
	p.pop()
	p.add(n)
}

func (p *parser) program() {
	for p.tok != EOF {
		p.command()
	}
}

func (p *parser) commands(stop ...token) (count int) {
	for p.tok != EOF {
		for _, tok := range stop {
			if p.peek(tok) {
				return
			}
		}
		p.command()
		count++
	}
	return
}

func (p *parser) command() {
	switch {
	case p.got(COMMENT):
		com := comment{
			text: p.lval,
		}
		p.add(com)
	case p.got('\n'), p.got(COMMENT):
		if p.tok != EOF {
			p.command()
		}
	case p.got(LPAREN):
		var sub subshell
		p.push(&sub.stmts)
		if p.commands(RPAREN) == 0 {
			p.errWantedStr("command")
		}
		p.want(RPAREN)
		p.popAdd(sub)
	case p.got(LBRACE):
		var bl block
		p.push(&bl.stmts)
		if p.commands(RBRACE) == 0 {
			p.errWantedStr("command")
		}
		p.want(RBRACE)
		p.popAdd(bl)
	case p.got(IF):
		var ifs ifStmt
		p.push(&ifs.cond)
		p.command()
		p.pop()
		p.want(THEN)
		p.push(&ifs.thenStmts)
		p.commands(FI, ELIF, ELSE)
		p.pop()
		p.push(&ifs.elifs)
		for p.got(ELIF) {
			var elf elif
			p.push(&elf.cond)
			p.command()
			p.pop()
			p.want(THEN)
			p.push(&elf.thenStmts)
			p.commands(FI, ELIF, ELSE)
			p.popAdd(elf)
		}
		if p.got(ELSE) {
			p.pop()
			p.push(&ifs.elseStmts)
			p.commands(FI)
		}
		p.want(FI)
		p.popAdd(ifs)
	case p.got(WHILE):
		var whl whileStmt
		p.push(&whl.cond)
		p.command()
		p.pop()
		p.want(DO)
		p.push(&whl.doStmts)
		p.commands(DONE)
		p.want(DONE)
		p.popAdd(whl)
	case p.got(WORD):
		var cmd command
		p.push(&cmd.args)
		p.add(lit{val: p.lval})
		first := p.lpos
	args:
		for p.tok != EOF {
			switch {
			case p.got(WORD):
				p.add(lit{val: p.lval})
			case p.got(AND):
				cmd.background = true
				break args
			case p.got(LAND):
				p.binaryExpr(LAND, cmd)
				return
			case p.got(OR):
				p.binaryExpr(OR, cmd)
				return
			case p.got(LOR):
				p.binaryExpr(LOR, cmd)
				return
			case p.got(LPAREN):
				if !identRe.MatchString(p.lval) {
					p.posErr(first, "invalid func name %q", p.lval)
					break args
				}
				fun := funcDecl{
					name: lit{val: p.lval},
				}
				p.want(RPAREN)
				p.push(&fun.body)
				p.command()
				p.pop()
				p.popAdd(fun)
				return
			case p.gotRedirect():
			case p.got(SEMICOLON):
				break args
			case p.got('\n'):
				break args
			default:
				p.errAfterStr("command")
			}
		}
		p.popAdd(cmd)
	default:
		p.errWantedStr("command")
	}
}

func (p *parser) binaryExpr(op token, left node) {
	b := binaryExpr{op: op}
	p.push(&b.Y)
	p.command()
	p.pop()
	b.X = left
	p.popAdd(b)
}

func (p *parser) gotRedirect() bool {
	var r redirect
	switch {
	case p.got(GTR):
		r.op = GTR
		if p.got(AND) {
			p.want(WORD)
			r.obj = lit{val: "&" + p.lval}
		} else {
			p.want(WORD)
			r.obj = lit{val: p.lval}
		}
	case p.got(SHR):
		r.op = SHR
		p.want(WORD)
		r.obj = lit{val: p.lval}
	case p.got(LSS):
		r.op = LSS
		p.want(WORD)
		r.obj = lit{val: p.lval}
	default:
		return false
	}
	p.add(r)
	return true
}
<|endoftext|>


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

package id3v2

import (
	"errors"
	"io"
)

const frameHeaderSize = 10

var ErrUnsupportedVersion = errors.New("unsupported version of ID3 tag")
var errBlankFrame = errors.New("id or size of frame are blank")

type frameHeader struct {
	ID       string
	BodySize int64
}

// parse finds ID3v2 tag in rd and parses it to tag considering opts.
// If rd is smaller than expected, it returns ErrSmallHeaderSize.
func (tag *Tag) parse(rd io.Reader, opts Options) error {
	if rd == nil {
		return errors.New("rd is nil")
	}

	header, err := parseHeader(rd)
	if err == errNoTag || err == io.EOF {
		tag.init(rd, 0, 4)
		return nil
	}
	if err != nil {
		return errors.New("error by parsing tag header: " + err.Error())
	}
	if header.Version < 3 {
		return ErrUnsupportedVersion
	}

	tag.init(rd, tagHeaderSize+header.FramesSize, header.Version)
	if !opts.Parse {
		return nil
	}
	return tag.parseFrames(opts)
}

func (tag *Tag) init(rd io.Reader, originalSize int64, version byte) {
	tag.DeleteAllFrames()

	tag.reader = rd
	tag.originalSize = originalSize
	tag.version = version
	tag.setDefaultEncoding(version)
}

func (tag *Tag) setDefaultEncoding(version byte) {
	if version == 4 {
		tag.defaultEncoding = EncodingUTF8
	} else {
		tag.defaultEncoding = EncodingISO
	}
}

func (tag *Tag) parseFrames(opts Options) error {
	framesSize := tag.originalSize - tagHeaderSize

	// Convert descriptions, specified by user in opts.ParseFrames, to IDs.
	parseIDs := make(map[string]bool, len(opts.ParseFrames))
	for _, description := range opts.ParseFrames {
		parseIDs[tag.CommonID(description)] = true
	}

	buf := getByteSlice(32 * 1024)
	defer putByteSlice(buf)
	for framesSize > 0 {
		header, err := parseFrameHeader(buf, tag.reader)
		if err == io.EOF || err == errBlankFrame || err == ErrInvalidSizeFormat {
			break
		}
		if err != nil {
			return err
		}
		id := header.ID
		bodySize := header.BodySize

		framesSize -= frameHeaderSize + bodySize

		bodyRd := getLimitedReader(tag.reader, bodySize)
		defer putLimitedReader(bodyRd)

		// If user set opts.ParseFrames and frame ID is not there,
		// skip this frame.
		if len(parseIDs) > 0 && !parseIDs[id] {
			if err := skipReaderBuf(bodyRd, buf); err != nil {
				return err
			}
			continue
		}

		frame, err := parseFrameBody(id, bodyRd)
		if err != nil && err != io.EOF {
			return err
		}

		tag.AddFrame(id, frame)

		if len(parseIDs) > 0 {
			// If the frame can be only one in tag,
			// don't take into consideration more frames with id.
			if !mustFrameBeInSequence(id) {
				delete(parseIDs, id)

				// And if it was last ID in parseIDs, we don't need to parse
				// other frames, so break the parsing.
				if len(parseIDs) == 0 {
					break
				}
			}
		}

		if err == io.EOF {
			break
		}
	}

	return nil
}

func parseFrameHeader(buf []byte, rd io.Reader) (frameHeader, error) {
	var header frameHeader

	if len(buf) < frameHeaderSize {
		return header, errors.New("parseFrameHeader: buf is smaller than frame header size")
	}

	fhBuf := buf[:frameHeaderSize]
	if _, err := rd.Read(fhBuf); err != nil {
		return header, err
	}

	id := string(fhBuf[:4])
	bodySize, err := parseSize(fhBuf[4:8])
	if err != nil {
		return header, err
	}

	if id == "" || bodySize == 0 {
		return header, errBlankFrame
	}

	header.ID = id
	header.BodySize = bodySize
	return header, nil
}

// skipReaderBuf just reads rd until io.EOF.
func skipReaderBuf(rd io.Reader, buf []byte) error {
	for {
		_, err := rd.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func parseFrameBody(id string, rd io.Reader) (Framer, error) {
	if id[0] == 'T' {
		return parseTextFrame(rd)
	}

	if parseFunc, exists := parsers[id]; exists {
		return parseFunc(rd)
	}

	return parseUnknownFrame(rd)
}
<commit_msg>Delete useless comments in parse.go<commit_after>// Copyright 2016 Albert Nigmatzianov. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package id3v2

import (
	"errors"
	"io"
)

const frameHeaderSize = 10

var ErrUnsupportedVersion = errors.New("unsupported version of ID3 tag")
var errBlankFrame = errors.New("id or size of frame are blank")

type frameHeader struct {
	ID       string
	BodySize int64
}

// parse finds ID3v2 tag in rd and parses it to tag considering opts.
// If rd is smaller than expected, it returns ErrSmallHeaderSize.
func (tag *Tag) parse(rd io.Reader, opts Options) error {
	if rd == nil {
		return errors.New("rd is nil")
	}

	header, err := parseHeader(rd)
	if err == errNoTag || err == io.EOF {
		tag.init(rd, 0, 4)
		return nil
	}
	if err != nil {
		return errors.New("error by parsing tag header: " + err.Error())
	}
	if header.Version < 3 {
		return ErrUnsupportedVersion
	}

	tag.init(rd, tagHeaderSize+header.FramesSize, header.Version)
	if !opts.Parse {
		return nil
	}
	return tag.parseFrames(opts)
}

func (tag *Tag) init(rd io.Reader, originalSize int64, version byte) {
	tag.DeleteAllFrames()

	tag.reader = rd
	tag.originalSize = originalSize
	tag.version = version
	tag.setDefaultEncoding(version)
}

func (tag *Tag) setDefaultEncoding(version byte) {
	if version == 4 {
		tag.defaultEncoding = EncodingUTF8
	} else {
		tag.defaultEncoding = EncodingISO
	}
}

func (tag *Tag) parseFrames(opts Options) error {
	framesSize := tag.originalSize - tagHeaderSize

	// Convert descriptions, specified by user in opts.ParseFrames, to IDs.
	parseIDs := make(map[string]bool, len(opts.ParseFrames))
	for _, description := range opts.ParseFrames {
		parseIDs[tag.CommonID(description)] = true
	}

	buf := getByteSlice(32 * 1024)
	defer putByteSlice(buf)
	for framesSize > 0 {
		header, err := parseFrameHeader(buf, tag.reader)
		if err == io.EOF || err == errBlankFrame || err == ErrInvalidSizeFormat {
			break
		}
		if err != nil {
			return err
		}
		id := header.ID
		bodySize := header.BodySize

		framesSize -= frameHeaderSize + bodySize

		bodyRd := getLimitedReader(tag.reader, bodySize)
		defer putLimitedReader(bodyRd)

		if len(parseIDs) > 0 && !parseIDs[id] {
			if err := skipReaderBuf(bodyRd, buf); err != nil {
				return err
			}
			continue
		}

		frame, err := parseFrameBody(id, bodyRd)
		if err != nil && err != io.EOF {
			return err
		}

		tag.AddFrame(id, frame)

		if len(parseIDs) > 0 {
			if !mustFrameBeInSequence(id) {
				delete(parseIDs, id)

				// If it was last ID in parseIDs, we don't need to parse
				// other frames, so end the parsing.
				if len(parseIDs) == 0 {
					break
				}
			}
		}

		if err == io.EOF {
			break
		}
	}

	return nil
}

func parseFrameHeader(buf []byte, rd io.Reader) (frameHeader, error) {
	var header frameHeader

	if len(buf) < frameHeaderSize {
		return header, errors.New("parseFrameHeader: buf is smaller than frame header size")
	}

	fhBuf := buf[:frameHeaderSize]
	if _, err := rd.Read(fhBuf); err != nil {
		return header, err
	}

	id := string(fhBuf[:4])
	bodySize, err := parseSize(fhBuf[4:8])
	if err != nil {
		return header, err
	}

	if id == "" || bodySize == 0 {
		return header, errBlankFrame
	}

	header.ID = id
	header.BodySize = bodySize
	return header, nil
}

// skipReaderBuf just reads rd until io.EOF.
func skipReaderBuf(rd io.Reader, buf []byte) error {
	for {
		_, err := rd.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func parseFrameBody(id string, rd io.Reader) (Framer, error) {
	if id[0] == 'T' {
		return parseTextFrame(rd)
	}

	if parseFunc, exists := parsers[id]; exists {
		return parseFunc(rd)
	}

	return parseUnknownFrame(rd)
}
<|endoftext|>


<commit_before>package client

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
)

type HTTPRemoteOptions struct {
	MetadataPath string
	TargetsPath  string
	UserAgent    string
}

func HTTPRemoteStore(baseURL string, opts *HTTPRemoteOptions) (RemoteStore, error) {
	if !strings.HasPrefix(baseURL, "http") {
		return nil, ErrInvalidURL{baseURL}
	}
	if opts == nil {
		opts = &HTTPRemoteOptions{}
	}
	if opts.TargetsPath == "" {
		opts.TargetsPath = "targets"
	}
	return &httpRemoteStore{baseURL, opts}, nil
}

type httpRemoteStore struct {
	baseURL string
	opts    *HTTPRemoteOptions
}

func (h *httpRemoteStore) GetMeta(name string) (io.ReadCloser, int64, error) {
	return h.get(path.Join(h.opts.MetadataPath, name))
}

func (h *httpRemoteStore) GetTarget(name string) (io.ReadCloser, int64, error) {
	return h.get(path.Join(h.opts.TargetsPath, name))
}

func (h *httpRemoteStore) get(s string) (io.ReadCloser, int64, error) {
	u := h.url(s)
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return nil, 0, err
	}
	if h.opts.UserAgent != "" {
		req.Header.Set("User-Agent", h.opts.UserAgent)
	}
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, 0, err
	}

	if res.StatusCode == http.StatusNotFound {
		res.Body.Close()
		return nil, 0, ErrNotFound{s}
	} else if res.StatusCode != http.StatusOK {
		res.Body.Close()
		return nil, 0, &url.Error{
			Op:  "GET",
			URL: u,
			Err: fmt.Errorf("unexpected HTTP status %d", res.StatusCode),
		}
	}

	size, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 0)
	if err != nil {
		return res.Body, -1, nil
	}
	return res.Body, size, nil
}

func (h *httpRemoteStore) url(path string) string {
	if !strings.HasPrefix(path, "/") {
		path = "/" + path
	}
	return h.baseURL + path
}
<commit_msg>tweaks for demo<commit_after>package client

import (
	"crypto/tls"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"
)

type HTTPRemoteOptions struct {
	MetadataPath string
	TargetsPath  string
	UserAgent    string
}

func HTTPRemoteStore(baseURL string, opts *HTTPRemoteOptions) (RemoteStore, error) {
	if !strings.HasPrefix(baseURL, "http") {
		return nil, ErrInvalidURL{baseURL}
	}
	if opts == nil {
		opts = &HTTPRemoteOptions{}
	}
	if opts.TargetsPath == "" {
		opts.TargetsPath = "targets"
	}
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	return &httpRemoteStore{baseURL, opts, client}, nil
}

type httpRemoteStore struct {
	baseURL string
	opts    *HTTPRemoteOptions
	client  *http.Client
}

func (h *httpRemoteStore) GetMeta(name string) (io.ReadCloser, int64, error) {
	return h.get(path.Join(h.opts.MetadataPath, name))
}

func (h *httpRemoteStore) GetTarget(name string) (io.ReadCloser, int64, error) {
	return h.get(path.Join(h.opts.TargetsPath, name))
}

func (h *httpRemoteStore) get(s string) (io.ReadCloser, int64, error) {
	u := h.url(s)
	fmt.Println("###########")
	fmt.Println(u)
	fmt.Println("###########")
	req, err := http.NewRequest("GET", u, nil)
	if err != nil {
		return nil, 0, err
	}
	if h.opts.UserAgent != "" {
		req.Header.Set("User-Agent", h.opts.UserAgent)
	}
	res, err := h.client.Do(req)
	if err != nil {
		return nil, 0, err
	}

	if res.StatusCode == http.StatusNotFound {
		res.Body.Close()
		return nil, 0, ErrNotFound{s}
	} else if res.StatusCode != http.StatusOK {
		res.Body.Close()
		return nil, 0, &url.Error{
			Op:  "GET",
			URL: u,
			Err: fmt.Errorf("unexpected HTTP status %d", res.StatusCode),
		}
	}

	size, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 0)
	if err != nil {
		return res.Body, -1, nil
	}
	return res.Body, size, nil
}

func (h *httpRemoteStore) url(path string) string {
	if !strings.HasPrefix(path, "/") {
		path = "/" + path
	}
	return h.baseURL + path
}
<|endoftext|>