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

package main

import (
	"flag"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"

	"upspin.io/errors"
	"upspin.io/path"
	"upspin.io/upspin"
)

type copyState struct {
	state      *State
	flagSet    *flag.FlagSet // Used only to call Usage.
	numWorkers int
	verbose    bool
	recur      bool
}

func (c *copyState) logf(format string, args ...interface{}) {
	if c.verbose {
		log.Printf(format, args...)
	}
}

// A cpFile is a glob-expanded file name and an indication of whether
// it resides on Upspin.
type cpFile struct {
	path     string
	isUpspin bool
}

var (
	errExist    = errors.E(errors.Exist)
	errNotExist = errors.E(errors.NotExist)
	errIsDir    = errors.E(errors.IsDir)
)

func (s *State) copyCommand(fs *flag.FlagSet, src []string, dst string) {
	// TODO: Check for nugatory copies.
	cs := &copyState{
		state:      s,
		flagSet:    fs,
		numWorkers: intFlag(fs, "n"),
		recur:      boolFlag(fs, "R"),
		verbose:    boolFlag(fs, "v"),
	}
	// Glob the paths.
	var files []cpFile
	for _, file := range src {
		files = append(files, cs.glob(file)...)
	}
	files = append(files, cs.glob(dst)...)
	srcFiles, dstFile := files[:len(files)-1], files[len(files)-1] // We are guaranteed at least two entries in files.
	if s.isDir(dstFile) {
		s.copyToDir(cs, srcFiles, dstFile)
		return
	}
	if len(src) != 1 {
		s.failf("copying multiple files but %s is not a directory", dstFile.path)
		cs.flagSet.Usage()
	}
	if cs.recur {
		s.failf("recursive copy requires that final argument (%s) be an existing directory", dstFile.path)
		cs.flagSet.Usage()
	}
	s.copyToFile(cs, srcFiles[0], dstFile)
}

// isDir reports whether the file is a directory either in Upspin
// or in the local file system.
func (s *State) isDir(cf cpFile) bool {
	if cf.isUpspin {
		entry, err := s.client.Lookup(upspin.PathName(cf.path), true)
		// Report the error here if it's anything odd, because otherwise
		// we'll report "not a directory" misleadingly.
		if err != nil && !errors.Match(errNotExist, err) {
			log.Printf("%q: %v", cf.path, err)
		}
		return err == nil && entry.IsDir()
	}
	// Not an Upspin name. Is it a local directory?
	info, err := os.Stat(cf.path)
	return err == nil && info.IsDir()
}

// open opens the file regardless of its location.
func (s *State) open(file cpFile) (io.ReadCloser, error) {
	if s.isDir(file) {
		return nil, errors.E(upspin.PathName(file.path), errors.IsDir)
	}
	if file.isUpspin {
		return s.client.Open(upspin.PathName(file.path))
	}
	return os.Open(file.path)
}

// create creates the file regardless of its location.
func (s *State) create(file cpFile) (io.WriteCloser, error) {
	if file.isUpspin {
		fd, err := s.client.Create(upspin.PathName(file.path))
		return fd, err
	}
	fd, err := os.Create(file.path)
	return fd, err
}

// createInDir create file 'base' in directory 'dir' regardless of the
// directory's location.
func (s *State) createInDir(dir cpFile, base string) (string, io.WriteCloser, error) {
	if dir.isUpspin {
		to := path.Join(upspin.PathName(dir.path), base)
		fd, err := s.client.Create(to)
		return string(to), fd, err
	}
	to := filepath.Join(dir.path, base)
	fd, err := os.Create(to)
	return to, fd, err
}

// copyWork is the unit of work passed to the copy worker.
type copyWork struct {
	src    string
	reader io.ReadCloser
	dst    string
	writer io.WriteCloser
}

// copyToDir copies, in parallel, the source files to the destination directory.
// It is a wrapper for copyDir, but holds the single work channel and waitgroup.
func (s *State) copyToDir(cs *copyState, src []cpFile, dir cpFile) {
	work := make(chan copyWork) // No need for buffering.
	var wait sync.WaitGroup

	// Launch the copier.
	go s.copyDir(cs, true, work, &wait, src, dir)

	// Start the workers.
	wait.Add(cs.numWorkers)
	for i := 0; i < cs.numWorkers; i++ {
		go cs.worker(work, &wait)
	}

	wait.Wait()
}

// copyDir copies, in parallel, the source files to the destination directory.
// It recurs if -R is set and a source is a subdirectory.
func (s *State) copyDir(cs *copyState, doClose bool, work chan copyWork, wait *sync.WaitGroup, src []cpFile, dir cpFile) {
	// Deliver work to the workers.
	for _, from := range src {
		reader, err := s.open(from)
		if cs.recur && errors.Match(errIsDir, err) {
			// If the problem is that from is a directory but have -R,
			// recur on the contents.
			cs.logf("recursive descent into %s", from.path)
			newFiles, err := s.contents(cs, from)
			if len(newFiles) == 0 && err != nil {
				continue
			}
			// May need to make subdirectory (even if it will have no files).
			subDir := dir
			if dir.isUpspin {
				// Rather than use the libraries and a lot of casting, it's easiest just to cat the strings here.
				subDir.path = subDir.path + "/" + filepath.Base(from.path) // TODO: is filepath.Base OK?
				_, err := s.client.MakeDirectory(upspin.PathName(subDir.path))
				if err != nil && !errors.Match(errExist, err) {
					s.fail(err)
					continue
				}
			} else {
				subDir.path = filepath.Join(subDir.path, filepath.Base(from.path))
				err := os.Mkdir(subDir.path, 0755) // TODO: Mode.
				if err != nil && !os.IsExist(err) {
					s.fail(err)
					continue
				}
			}
			s.copyDir(cs, false, work, wait, newFiles, subDir)
			continue
		}
		if err != nil {
			s.fail(err)
			continue
		}
		to, writer, err := s.createInDir(dir, filepath.Base(from.path))
		if err != nil {
			s.fail(err)
			reader.Close()
			continue
		}
		work <- copyWork{
			src:    from.path,
			reader: reader,
			dst:    to,
			writer: writer,
		}
	}
	if doClose {
		close(work)
	}
}

// copyToFile copies the source to the destination.
func (s *State) copyToFile(cs *copyState, src, dst cpFile) {
	// If both are in Upspin, we can avoid touching the data by copying
	// just the references.
	if src.isUpspin && dst.isUpspin {
		_, err := s.client.PutDuplicate(upspin.PathName(src.path), upspin.PathName(dst.path))
		if err == nil {
			return
		}
		if errors.Match(errExist, err) {
			// File already exists, which PutDuplicate doesn't handle.
			// For now, just fall through. We could remove it and retry
			// but that's a little scary.
		} else {
			s.fail(err)
		}
	}
	reader, err := s.open(src)
	if err != nil {
		s.fail(err)
		s.exitCode = 1
		return
	}
	writer, err := s.create(dst)
	if err != nil {
		s.fail(err)
		s.exitCode = 1
		reader.Close()
		return
	}
	copy := copyWork{
		src:    src.path,
		reader: reader,
		dst:    dst.path,
		writer: writer,
	}
	cs.doCopy(copy)
}

func (cs *copyState) worker(work chan copyWork, wait *sync.WaitGroup) {
	defer wait.Done()
	for copy := range work {
		cs.doCopy(copy)
	}
}

func (cs *copyState) doCopy(copy copyWork) {
	cs.logf("start cp %s %s", copy.src, copy.dst)
	defer func() {
		cs.logf("end cp %s %s", copy.src, copy.dst)
		copy.reader.Close()
		err := copy.writer.Close()
		if err != nil {
			cs.state.fail(err)
		}
	}()
	_, err := io.Copy(copy.writer, copy.reader)
	if err != nil {
		cs.state.fail(err)
	}
}

// glob glob-expands the argument, which could be a local file
// name or an Upspin path name.
func (cs *copyState) glob(pattern string) (files []cpFile) {
	parsed, err := path.Parse(upspin.PathName(pattern))
	if err == nil {
		// It's an Upspin path.
		for _, path := range cs.state.globUpspin(parsed.String()) {
			files = append(files, cpFile{
				path:     string(path),
				isUpspin: true,
			})
		}
		return files
	}
	// It's a local path.
	for _, path := range cs.state.globLocal(pattern) {
		files = append(files, cpFile{
			path:     path,
			isUpspin: false,
		})
	}
	return files
}

// contents return the top-level contents of dir as a slice of cpFiles.
func (s *State) contents(cs *copyState, dir cpFile) ([]cpFile, error) {
	if dir.isUpspin {
		entries, err := s.client.Glob(upspin.AllFilesGlob(upspin.PathName(dir.path)))
		if err != nil {
			s.fail(err)
			// OK to continue; there may still be files.
		}
		files := make([]cpFile, len(entries))
		for i, entry := range entries {
			files[i] = cpFile{
				path:     string(entry.Name),
				isUpspin: true,
			}
		}
		return files, err
	}
	// Local directory.
	fd, err := os.Open(dir.path)
	if err != nil {
		s.fail(err)
		return nil, err
	}
	defer fd.Close()
	names, err := fd.Readdirnames(0)
	if err != nil {
		s.fail(err)
		// OK to continue; there may still be files.
	}
	files := make([]cpFile, len(names))
	for i, name := range names {
		files[i] = cpFile{
			path:     filepath.Join(dir.path, name),
			isUpspin: false,
		}
	}
	return files, err
}
<commit_msg>cmd/upspin: make fast copy work if the command-line destination is a directory<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"flag"
	"io"
	"log"
	"os"
	"path/filepath"
	"sync"

	"upspin.io/errors"
	"upspin.io/path"
	"upspin.io/upspin"
)

type copyState struct {
	state      *State
	flagSet    *flag.FlagSet // Used only to call Usage.
	numWorkers int
	verbose    bool
	recur      bool
}

func (c *copyState) logf(format string, args ...interface{}) {
	if c.verbose {
		log.Printf(format, args...)
	}
}

// A cpFile is a glob-expanded file name and an indication of whether
// it resides on Upspin.
type cpFile struct {
	path     string
	isUpspin bool
}

var (
	errExist    = errors.E(errors.Exist)
	errNotExist = errors.E(errors.NotExist)
	errIsDir    = errors.E(errors.IsDir)
)

func (s *State) copyCommand(fs *flag.FlagSet, src []string, dst string) {
	// TODO: Check for nugatory copies.
	cs := &copyState{
		state:      s,
		flagSet:    fs,
		numWorkers: intFlag(fs, "n"),
		recur:      boolFlag(fs, "R"),
		verbose:    boolFlag(fs, "v"),
	}
	// Glob the paths.
	var files []cpFile
	for _, file := range src {
		files = append(files, cs.glob(file)...)
	}
	files = append(files, cs.glob(dst)...)
	srcFiles, dstFile := files[:len(files)-1], files[len(files)-1] // We are guaranteed at least two entries in files.
	if s.isDir(dstFile) {
		s.copyToDir(cs, srcFiles, dstFile)
		return
	}
	if len(src) != 1 {
		s.failf("copying multiple files but %s is not a directory", dstFile.path)
		cs.flagSet.Usage()
	}
	if cs.recur {
		s.failf("recursive copy requires that final argument (%s) be an existing directory", dstFile.path)
		cs.flagSet.Usage()
	}
	s.copyToFile(cs, srcFiles[0], dstFile)
}

// isDir reports whether the file is a directory either in Upspin
// or in the local file system.
func (s *State) isDir(cf cpFile) bool {
	if cf.isUpspin {
		entry, err := s.client.Lookup(upspin.PathName(cf.path), true)
		// Report the error here if it's anything odd, because otherwise
		// we'll report "not a directory" misleadingly.
		if err != nil && !errors.Match(errNotExist, err) {
			log.Printf("%q: %v", cf.path, err)
		}
		return err == nil && entry.IsDir()
	}
	// Not an Upspin name. Is it a local directory?
	info, err := os.Stat(cf.path)
	return err == nil && info.IsDir()
}

// open opens the file regardless of its location.
func (s *State) open(file cpFile) (io.ReadCloser, error) {
	if s.isDir(file) {
		return nil, errors.E(upspin.PathName(file.path), errors.IsDir)
	}
	if file.isUpspin {
		return s.client.Open(upspin.PathName(file.path))
	}
	return os.Open(file.path)
}

// create creates the file regardless of its location.
func (s *State) create(file cpFile) (io.WriteCloser, error) {
	if file.isUpspin {
		fd, err := s.client.Create(upspin.PathName(file.path))
		return fd, err
	}
	fd, err := os.Create(file.path)
	return fd, err
}

// createInDir create file 'base' in directory 'dir' regardless of the
// directory's location.
func (s *State) createInDir(dir cpFile, base string) (string, io.WriteCloser, error) {
	if dir.isUpspin {
		to := path.Join(upspin.PathName(dir.path), base)
		fd, err := s.client.Create(to)
		return string(to), fd, err
	}
	to := filepath.Join(dir.path, base)
	fd, err := os.Create(to)
	return to, fd, err
}

// copyWork is the unit of work passed to the copy worker.
type copyWork struct {
	src    string
	reader io.ReadCloser
	dst    string
	writer io.WriteCloser
}

// copyToDir copies, in parallel, the source files to the destination directory.
// It is a wrapper for copyDir, but holds the single work channel and waitgroup.
func (s *State) copyToDir(cs *copyState, src []cpFile, dir cpFile) {
	work := make(chan copyWork) // No need for buffering.
	var wait sync.WaitGroup

	// Launch the copier.
	go s.copyDir(cs, true, work, &wait, src, dir)

	// Start the workers.
	wait.Add(cs.numWorkers)
	for i := 0; i < cs.numWorkers; i++ {
		go cs.worker(work, &wait)
	}

	wait.Wait()
}

// copyDir copies, in parallel, the source files to the destination directory.
// It recurs if -R is set and a source is a subdirectory.
func (s *State) copyDir(cs *copyState, doClose bool, work chan copyWork, wait *sync.WaitGroup, src []cpFile, dir cpFile) {
	// Deliver work to the workers.
	for _, from := range src {
		if dir.isUpspin && from.isUpspin {
			// Try a fast copy. It can fail but that's OK.
			dst := path.Join(upspin.PathName(dir.path), filepath.Base(from.path))
			cs.logf("try fast copy to %s", dst)
			if s.fastCopy(upspin.PathName(from.path), dst) == nil {
				continue
			}
		}
		reader, err := s.open(from)
		if cs.recur && errors.Match(errIsDir, err) {
			// If the problem is that from is a directory but have -R,
			// recur on the contents.
			cs.logf("recursive descent into %s", from.path)
			newFiles, err := s.contents(cs, from)
			if len(newFiles) == 0 && err != nil {
				continue
			}
			// May need to make subdirectory (even if it will have no files).
			subDir := dir
			if dir.isUpspin {
				// Rather than use the libraries and a lot of casting, it's easiest just to cat the strings here.
				subDir.path = subDir.path + "/" + filepath.Base(from.path) // TODO: is filepath.Base OK?
				_, err := s.client.MakeDirectory(upspin.PathName(subDir.path))
				if err != nil && !errors.Match(errExist, err) {
					s.fail(err)
					continue
				}
			} else {
				subDir.path = filepath.Join(subDir.path, filepath.Base(from.path))
				err := os.Mkdir(subDir.path, 0755) // TODO: Mode.
				if err != nil && !os.IsExist(err) {
					s.fail(err)
					continue
				}
			}
			s.copyDir(cs, false, work, wait, newFiles, subDir)
			continue
		}
		if err != nil {
			s.fail(err)
			continue
		}
		to, writer, err := s.createInDir(dir, filepath.Base(from.path))
		if err != nil {
			s.fail(err)
			reader.Close()
			continue
		}
		work <- copyWork{
			src:    from.path,
			reader: reader,
			dst:    to,
			writer: writer,
		}
	}
	if doClose {
		close(work)
	}
}

// copyToFile copies the source to the destination.
func (s *State) copyToFile(cs *copyState, src, dst cpFile) {
	cs.logf("start cp %s %s", src.path, dst.path)
	defer cs.logf("end cp %s %s", src.path, dst.path)
	// If both are in Upspin, we can avoid touching the data by copying
	// just the references.
	if src.isUpspin && dst.isUpspin {
		cs.logf("try fast copy to %s", dst)
		err := s.fastCopy(upspin.PathName(src.path), upspin.PathName(dst.path))
		if err == nil {
			return
		}
	}
	reader, err := s.open(src)
	if err != nil {
		s.fail(err)
		s.exitCode = 1
		return
	}
	writer, err := s.create(dst)
	if err != nil {
		s.fail(err)
		s.exitCode = 1
		reader.Close()
		return
	}
	copy := copyWork{
		src:    src.path,
		reader: reader,
		dst:    dst.path,
		writer: writer,
	}
	cs.doCopy(copy)
}

// fastCopy copies the source to the destination using the references rather than the data.
// If it fails, PutDuplicate failed because the file exists or the source is a directory.
// (Any other error is unexpected and exits the copy command.)
// The caller may be able to retry with a regular copy.
func (s *State) fastCopy(src, dst upspin.PathName) error {
	_, err := s.client.PutDuplicate(src, dst)
	if err == nil {
		return nil
	}
	if errors.Match(errExist, err) {
		// File already exists, which PutDuplicate doesn't handle.
		// Use regular copy. We could remove it and retry
		// but that's a little scary.
		return err
	}
	if errors.Match(errIsDir, err) {
		// Oops, we have a directory. Retry.
		return err
	}
	// Unexpected error. Die.
	s.fail(err)
	return nil
}

func (cs *copyState) worker(work chan copyWork, wait *sync.WaitGroup) {
	defer wait.Done()
	for copy := range work {
		cs.doCopy(copy)
	}
}

func (cs *copyState) doCopy(copy copyWork) {
	defer func() {
		copy.reader.Close()
		err := copy.writer.Close()
		if err != nil {
			cs.state.fail(err)
		}
	}()
	_, err := io.Copy(copy.writer, copy.reader)
	if err != nil {
		cs.state.fail(err)
	}
}

// glob glob-expands the argument, which could be a local file
// name or an Upspin path name.
func (cs *copyState) glob(pattern string) (files []cpFile) {
	parsed, err := path.Parse(upspin.PathName(pattern))
	if err == nil {
		// It's an Upspin path.
		for _, path := range cs.state.globUpspin(parsed.String()) {
			files = append(files, cpFile{
				path:     string(path),
				isUpspin: true,
			})
		}
		return files
	}
	// It's a local path.
	for _, path := range cs.state.globLocal(pattern) {
		files = append(files, cpFile{
			path:     path,
			isUpspin: false,
		})
	}
	return files
}

// contents return the top-level contents of dir as a slice of cpFiles.
func (s *State) contents(cs *copyState, dir cpFile) ([]cpFile, error) {
	if dir.isUpspin {
		entries, err := s.client.Glob(upspin.AllFilesGlob(upspin.PathName(dir.path)))
		if err != nil {
			s.fail(err)
			// OK to continue; there may still be files.
		}
		files := make([]cpFile, len(entries))
		for i, entry := range entries {
			files[i] = cpFile{
				path:     string(entry.Name),
				isUpspin: true,
			}
		}
		return files, err
	}
	// Local directory.
	fd, err := os.Open(dir.path)
	if err != nil {
		s.fail(err)
		return nil, err
	}
	defer fd.Close()
	names, err := fd.Readdirnames(0)
	if err != nil {
		s.fail(err)
		// OK to continue; there may still be files.
	}
	files := make([]cpFile, len(names))
	for i, name := range names {
		files[i] = cpFile{
			path:     filepath.Join(dir.path, name),
			isUpspin: false,
		}
	}
	return files, err
}
<|endoftext|>


<commit_before>package parser

import (
	docker "github.com/docker/docker/builder/dockerfile/parser"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func parceEnv(line string) string {
	var tokenWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`)
	var str string

	line = strings.Replace(line, "ENV ", "", -1)
	if strings.Contains(line, "=") {
		str = line
	} else {
		slice := tokenWhitespace.Split(line, 2)
		str = slice[0] + "=" + `"` + strings.Join(slice[1:], " ") + `"`
	}
	str = strings.Replace(str, "\t", " ", -1)
	return "export " + str + "\n"
}

func parceCopy(line []string) string {
	if len(line) > 1 {
		line[1] = `"/opt/docker2subutai/` + strings.Replace(line[1], `"`, "", -1) + `"`
		return "cp -rf " + strings.Join(line[1:], " ") + "\n"
	}
	return ""
}

func parceRun(line []string) string {
	if len(line) > 1 {
		str, _ := strconv.Unquote(strings.Join(line[1:], " "))
		if !(strings.Contains(str, "ln") && (strings.Contains(str, "/dev/stdout") || strings.Contains(str, "/dev/stderr"))) {
			str = strings.Replace(str, "\t", " ", -1)
			// str = strings.Replace(str, " && ", "\n", -1)
			return str + "\n"
		}
	}
	return ""
}

func parceFrom(line []string) string {
	if len(line) > 1 {
		if strings.Contains(line[1], "debian") {
			return "debian"
		} else if strings.Contains(line[1], "ubuntu") {
			return "ubuntu"
		}
	}
	return ""
}

func parceCmd(line []string, isEntrypoint bool) string {
	if len(line) > 1 {
		str := strings.Join(line[1:], " ")
		str = strings.Replace(str, "\t", " ", -1)
		if isEntrypoint {
			str, _ = strconv.Unquote(str)
		}
		return str
	}
	return ""
}

func Parce(name string) (out, env, cmd, image, user, wdir string) {
	file, _ := os.Open(name)
	node, _ := docker.Parse(file)
	file.Close()

	for _, n := range node.Children {
		if str := strings.Fields(n.Dump()); len(str) > 0 {
			switch str[0] {
			case "env":
				// env = env + parceEnv(str)
				env = env + parceEnv(n.Original)
			case "run":
				out = out + parceRun(str)
			case "add", "copy":
				out = out + parceCopy(str)
			case "from":
				image = parceFrom(str)
			case "cmd":
				cmd = cmd + parceCmd(str, false)
			case "entrypoint":
				cmd = cmd + parceCmd(str, true) + " "
			case "user":
				user, _ = strconv.Unquote(strings.Join(str[1:], ""))
			case "workdir":
				wdir, _ = strconv.Unquote(strings.Join(str[1:], ""))
			}
		}
	}
	if len(out) > 0 {
		return out, env, cmd, image, user, wdir
	}
	return
}
<commit_msg>d2s / added WORKDIR parsing support #156 added cd into install.sh (grafana test)<commit_after>package parser

import (
	docker "github.com/docker/docker/builder/dockerfile/parser"
	"os"
	"regexp"
	"strconv"
	"strings"
)

func parceEnv(line string) string {
	var tokenWhitespace = regexp.MustCompile(`[\t\v\f\r ]+`)
	var str string

	line = strings.Replace(line, "ENV ", "", -1)
	if strings.Contains(line, "=") {
		str = line
	} else {
		slice := tokenWhitespace.Split(line, 2)
		str = slice[0] + "=" + `"` + strings.Join(slice[1:], " ") + `"`
	}
	str = strings.Replace(str, "\t", " ", -1)
	return "export " + str + "\n"
}

func parceCopy(line []string) string {
	if len(line) > 1 {
		line[1] = `"/opt/docker2subutai/` + strings.Replace(line[1], `"`, "", -1) + `"`
		return "cp -rf " + strings.Join(line[1:], " ") + "\n"
	}
	return ""
}

func parceRun(line []string) string {
	if len(line) > 1 {
		str, _ := strconv.Unquote(strings.Join(line[1:], " "))
		if !(strings.Contains(str, "ln") && (strings.Contains(str, "/dev/stdout") || strings.Contains(str, "/dev/stderr"))) {
			str = strings.Replace(str, "\t", " ", -1)
			// str = strings.Replace(str, " && ", "\n", -1)
			return str + "\n"
		}
	}
	return ""
}

func parceFrom(line []string) string {
	if len(line) > 1 {
		if strings.Contains(line[1], "debian") {
			return "debian"
		} else if strings.Contains(line[1], "ubuntu") {
			return "ubuntu"
		}
	}
	return ""
}

func parceCmd(line []string, isEntrypoint bool) string {
	if len(line) > 1 {
		str := strings.Join(line[1:], " ")
		str = strings.Replace(str, "\t", " ", -1)
		if isEntrypoint {
			str, _ = strconv.Unquote(str)
		}
		return str
	}
	return ""
}

func Parce(name string) (out, env, cmd, image, user, wdir string) {
	file, _ := os.Open(name)
	node, _ := docker.Parse(file)
	file.Close()

	for _, n := range node.Children {
		if str := strings.Fields(n.Dump()); len(str) > 0 {
			switch str[0] {
			case "env":
				// env = env + parceEnv(str)
				env = env + parceEnv(n.Original)
			case "run":
				out = out + parceRun(str)
			case "add", "copy":
				out = out + parceCopy(str)
			case "from":
				image = parceFrom(str)
			case "cmd":
				cmd = cmd + parceCmd(str, false)
			case "entrypoint":
				cmd = cmd + parceCmd(str, true) + " "
			case "user":
				user, _ = strconv.Unquote(strings.Join(str[1:], ""))
			case "workdir":
				{
					wdir, _ = strconv.Unquote(strings.Join(str[1:], ""))
					out = out + "cd " + wdir + "\n"

				}
			}
		}
	}
	if len(out) > 0 {
		return out, env, cmd, image, user, wdir
	}
	return
}
<|endoftext|>


<commit_before>// HTTP JSON Gorilla RPC for golang
package json2

import (
  "encoding/json"
  "fmt"
  "io"
  "math/rand"
)

// clientRequest represents a JSON-RPC v2.0 request sent by a client.
type clientRequest struct {
  // A String containing the name of the method to be invoked.
  Method string `json:"method"`
  // Object to pass as request parameter to the method.
  Params interface{} `json:"params"`
  // The request id. This can be of any type. It is used to match the
  // response with the request that it is replying to.
  Id uint64 `json:"id"`
  // Always set to 2.0
  Jsonrpc string `json:"jsonrpc"`
}

// clientResponse represents a JSON-RPC response returned to a client.
type clientResponse struct {
  Result  *json.RawMessage `json:"result"`
  Error   interface{}      `json:"error"` // {"code": -32700, "message": "Parse error"}
  Id      uint64           `json:"id"`
  Jsonrpc string           `json:"jsonrpc"`
}

// EncodeClientRequest encodes parameters for a JSON-RPC v2.0 client request.
func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
  c := &clientRequest{
    Method:  method,
    Params:  args,
    Id:      uint64(rand.Int63()),
    Jsonrpc: "2.0",
  }
  return json.Marshal(c)
}

// DecodeClientResponse decodes the response body of a client request into
// the interface reply.
func DecodeClientResponse(r io.Reader, reply interface{}) error {
  var c clientResponse
  if err := json.NewDecoder(r).Decode(&c); err != nil {
    return err
  }
  if c.Error != nil {
    return fmt.Errorf("%v", c.Error)
  }
  return json.Unmarshal(*c.Result, reply)
}
<commit_msg>Added an Error type that knows how to print map[string]interface{}<commit_after>// HTTP JSON Gorilla RPC for golang
package json2

import (
  "encoding/json"
  "fmt"
  "io"
  "math/rand"
  "strings"
)

// clientRequest represents a JSON-RPC v2.0 request sent by a client.
type clientRequest struct {
  // A String containing the name of the method to be invoked.
  Method string `json:"method"`
  // Object to pass as request parameter to the method.
  Params interface{} `json:"params"`
  // The request id. This can be of any type. It is used to match the
  // response with the request that it is replying to.
  Id uint64 `json:"id"`
  // Always set to 2.0
  Jsonrpc string `json:"jsonrpc"`
}

// clientResponse represents a JSON-RPC response returned to a client.
type clientResponse struct {
  Result  *json.RawMessage `json:"result"`
  Error   interface{}      `json:"error"` // {"code": -32700, "message": "Parse error"}
  Id      uint64           `json:"id"`
  Jsonrpc string           `json:"jsonrpc"`
}

// EncodeClientRequest encodes parameters for a JSON-RPC v2.0 client request.
func EncodeClientRequest(method string, args interface{}) ([]byte, error) {
  c := &clientRequest{
    Method:  method,
    Params:  args,
    Id:      uint64(rand.Int63()),
    Jsonrpc: "2.0",
  }
  return json.Marshal(c)
}

type Error map[string]interface{}

func (e Error) Error() string {
  var parts []string
  for key, value := range e {
    parts = append(parts, fmt.Sprintf("%s: %s", key, value))
  }
  return strings.Join(parts, ", ")
}

// DecodeClientResponse decodes the response body of a client request into
// the interface reply.
func DecodeClientResponse(r io.Reader, reply interface{}) error {
  var c clientResponse
  if err := json.NewDecoder(r).Decode(&c); err != nil {
    return err
  }

  if c.Error != nil {
    if eror, ok := c.Error.(map[string]interface{}); ok {
      return Error(eror)
    } else {
      return fmt.Errorf("%v", c.Error)
    }
  }
  return json.Unmarshal(*c.Result, reply)
}
<|endoftext|>


<commit_before>package jwt_test

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"encoding/json"
	"strings"
	"testing"
	"time"

	"github.com/lestrrat/go-jwx/jwa"
	"github.com/lestrrat/go-jwx/jwt"
	"github.com/stretchr/testify/assert"
)

func TestSignature(t *testing.T) {
	alg := jwa.RS256
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if !assert.NoError(t, err, "RSA key generated") {
		return
	}

	t1 := jwt.New()
	signed, err := t1.Sign(alg, key)
	t.Run("parse (no signature verification)", func(t *testing.T) {
		t2, err := jwt.Parse(bytes.NewReader(signed))
		if !assert.NoError(t, err, `jwt.Parse should succeed`) {
			return
		}
		if !assert.Equal(t, t1, t2, `t1 == t2`) {
			return
		}
	})
	t.Run("parse (correct signature key)", func(t *testing.T) {
		t2, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(alg, &key.PublicKey))
		if !assert.NoError(t, err, `jwt.Parse should succeed`) {
			return
		}
		if !assert.Equal(t, t1, t2, `t1 == t2`) {
			return
		}
	})
	t.Run("parse (wrong signature algorithm)", func(t *testing.T) {
		_, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(jwa.RS512, &key.PublicKey))
		if !assert.Error(t, err, `jwt.Parse should fail`) {
			return
		}
	})
	t.Run("parse (wrong signature key)", func(t *testing.T) {
		pubkey := key.PublicKey
		pubkey.E = 0 // bogus value
		_, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(alg, &pubkey))
		if !assert.Error(t, err, `jwt.Parse should fail`) {
			return
		}
	})
}

func TestToken(t *testing.T) {
	t1 := jwt.New()
	if !assert.NoError(t, t1.Set(jwt.JwtIDKey, "AbCdEfG"), "setting jti should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.SubjectKey, "foobar@example.com"), "setting sub should work") {
		return
	}

	// Silly fix to remove monotonic element from time.Time obatained
	// from time.Now(). Without this, the equality comparison goes
	// ga-ga for golang tip (1.9)
	now := time.Unix(time.Now().Unix(), 0)
	if !assert.NoError(t, t1.Set(jwt.IssuedAtKey, now.Unix()), "setting iat to now should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.NotBeforeKey, now.Add(5*time.Second)), "setting nbf should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.ExpirationKey, now.Add(10*time.Second).Unix()), "setting exp should work") {
		return
	}
	if !assert.NoError(t, t1.Set("custom", "MyValue"), "setting custom should work") {
		return
	}

	jsonbuf1, err := json.MarshalIndent(t1, "", "  ")
	if !assert.NoError(t, err, "JSON marshal should succeed") {
		return
	}
	t.Logf("%s", jsonbuf1)

	var t2 jwt.Token
	if !assert.NoError(t, json.Unmarshal(jsonbuf1, &t2), "JSON unmarshal should succeed") {
		return
	}

	jsonbuf2, err := json.MarshalIndent(t2, "", "  ")
	if !assert.NoError(t, err, "JSON marshal should succeed") {
		return
	}
	t.Logf("%s", jsonbuf2)

	if !assert.Equal(t, t1, &t2, "tokens match") {
		return
	}
}

func TestGHIssue10(t *testing.T) {
	t.Run(jwt.IssuerKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.IssuerKey, "github.com/lestrrat/go-jwx")

		// This should succeed, because WithIssuer is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "t1.Verify should succeed") {
			return
		}

		// This should succeed, because WithIssuer is provided with same value
		if !assert.NoError(t, t1.Verify(jwt.WithIssuer(t1.Issuer())), "t1.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithIssuer("poop")), "t1.Verify should fail") {
			return
		}
	})
	t.Run(jwt.AudienceKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.AudienceKey, []string{
			"foo",
			"bar",
			"baz",
		})

		// This should succeed, because WithAudience is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "token.Verify should succeed") {
			return
		}

		// This should succeed, because WithAudience is provided, and its
		// value matches one of the audience values
		if !assert.NoError(t, t1.Verify(jwt.WithAudience("baz")), "token.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithAudience("poop")), "token.Verify should fail") {
			return
		}
	})
	t.Run(jwt.SubjectKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.SubjectKey, "github.com/lestrrat/go-jwx")

		// This should succeed, because WithSubject is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "token.Verify should succeed") {
			return
		}

		// This should succeed, because WithSubject is provided with same value
		if !assert.NoError(t, t1.Verify(jwt.WithSubject(t1.Subject())), "token.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithSubject("poop")), "token.Verify should fail") {
			return
		}
	})
	t.Run(jwt.NotBeforeKey, func(t *testing.T) {
		t1 := jwt.New()

		// NotBefore is set to future date
		tm := time.Now().Add(72 * time.Hour)
		t1.Set(jwt.NotBeforeKey, tm)

		// This should fail, because nbf is the future
		if !assert.Error(t, t1.Verify(), "token.Verify should fail") {
			return
		}

		// This should succeed, because we have given reaaaaaaly big skew
		// that is well enough to get us accepted
		if !assert.NoError(t, t1.Verify(jwt.WithAcceptableSkew(73*time.Hour)), "token.Verify should succeed") {
			return
		}

		// This should succeed, because we have given a time
		// that is well enough into the future
		if !assert.NoError(t, t1.Verify(jwt.WithClock(jwt.ClockFunc(func() time.Time { return tm.Add(time.Hour) }))), "token.Verify should succeed") {
			return
		}
	})
	t.Run(jwt.ExpirationKey, func(t *testing.T) {
		t1 := jwt.New()

		// issuedat = 1 Hr before current time
		tm := time.Now()
		t1.Set(jwt.IssuedAtKey, tm.Add(-1*time.Hour))

		// valid for 2 minutes only from IssuedAt
		t1.Set(jwt.ExpirationKey, tm.Add(-58*time.Minute))

		// This should fail, because exp is set in the past
		if !assert.Error(t, t1.Verify(), "token.Verify should fail") {
			return
		}

		// This should succeed, because we have given big skew
		// that is well enough to get us accepted
		if !assert.NoError(t, t1.Verify(jwt.WithAcceptableSkew(time.Hour)), "token.Verify should succeed (1)") {
			return
		}

		// This should succeed, because we have given a time
		// that is well enough into the past
		clock := jwt.ClockFunc(func() time.Time {
			return tm.Add(-59 * time.Minute)
		})
		if !assert.NoError(t, t1.Verify(jwt.WithClock(clock)), "token.Verify should succeed (2)") {
			return
		}
	})
}

func TestVerifyClaims(t *testing.T) {
	// GitHub issue #37: tokens are invalid in the second they are created (because Now() is not after IssuedAt())
	// Note that this has a very slight race condition as Now() here is a little bit earlier than Now() in the Verify() function.
	t.Run(jwt.IssuedAtKey+"+skew", func(t *testing.T) {
		token := jwt.New()
		now := time.Now().UTC()
		token.Set(jwt.IssuedAtKey, now)

		const DefaultSkew = 0

		if !assert.NoError(t, token.Verify(jwt.WithAcceptableSkew(DefaultSkew)), "token.Verify should validate tokens in the same second they are created") {
			if now.Equal(token.IssuedAt()) {
				t.Errorf("iat claim failed: iat == now")
			}
			return
		}
	})
}

const aLongLongTimeAgo = 233431200
const aLongLongTimeAgoString = "233431200"

func TestUnmarshal(t *testing.T) {
	testcases := []struct {
		Title    string
		JSON     string
		Expected func() *jwt.Token
	}{
		{
			Title: "single aud",
			JSON:  `{"aud":"foo"}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set("aud", "foo")
				return t
			},
		},
		{
			Title: "multiple aud's",
			JSON:  `{"aud":["foo","bar"]}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set("aud", []string{"foo", "bar"})
				return t
			},
		},
		{
			Title: "issuedAt",
			JSON:  `{"` + jwt.IssuedAtKey + `":` + aLongLongTimeAgoString + `}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set(jwt.IssuedAtKey, aLongLongTimeAgo)
				return t
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.Title, func(t *testing.T) {
			var token jwt.Token
			if !assert.NoError(t, json.Unmarshal([]byte(tc.JSON), &token), `json.Unmarshal should succeed`) {
				return
			}
			if !assert.Equal(t, tc.Expected(), &token, `token should match expeted value`) {
				return
			}

			var buf bytes.Buffer
			if !assert.NoError(t, json.NewEncoder(&buf).Encode(token), `json.Marshal should succeed`) {
				return
			}
			if !assert.Equal(t, tc.JSON, strings.TrimSpace(buf.String()), `json should match`) {
				return
			}
		})
	}
}

func TestGet(t *testing.T) {
	testcases := []struct {
		Title string
		Test  func(*testing.T, *jwt.Token)
		Token func() *jwt.Token
	}{
		{
			Title: `Get IssuedAt`,
			Test: func(t *testing.T, token *jwt.Token) {
				expected := time.Unix(aLongLongTimeAgo, 0).UTC()
				if !assert.Equal(t, expected, token.IssuedAt(), `IssuedAt should match`) {
					return
				}
			},
			Token: func() *jwt.Token {
				t := jwt.New()
				t.Set(jwt.IssuedAtKey, 233431200)
				return t
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.Title, func(t *testing.T) {
			tc.Test(t, tc.Token())
		})
	}
}
<commit_msg>Use jwt.WithClock option to avoid races<commit_after>package jwt_test

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"encoding/json"
	"strings"
	"testing"
	"time"

	"github.com/lestrrat/go-jwx/jwa"
	"github.com/lestrrat/go-jwx/jwt"
	"github.com/stretchr/testify/assert"
)

func TestSignature(t *testing.T) {
	alg := jwa.RS256
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if !assert.NoError(t, err, "RSA key generated") {
		return
	}

	t1 := jwt.New()
	signed, err := t1.Sign(alg, key)
	t.Run("parse (no signature verification)", func(t *testing.T) {
		t2, err := jwt.Parse(bytes.NewReader(signed))
		if !assert.NoError(t, err, `jwt.Parse should succeed`) {
			return
		}
		if !assert.Equal(t, t1, t2, `t1 == t2`) {
			return
		}
	})
	t.Run("parse (correct signature key)", func(t *testing.T) {
		t2, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(alg, &key.PublicKey))
		if !assert.NoError(t, err, `jwt.Parse should succeed`) {
			return
		}
		if !assert.Equal(t, t1, t2, `t1 == t2`) {
			return
		}
	})
	t.Run("parse (wrong signature algorithm)", func(t *testing.T) {
		_, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(jwa.RS512, &key.PublicKey))
		if !assert.Error(t, err, `jwt.Parse should fail`) {
			return
		}
	})
	t.Run("parse (wrong signature key)", func(t *testing.T) {
		pubkey := key.PublicKey
		pubkey.E = 0 // bogus value
		_, err := jwt.Parse(bytes.NewReader(signed), jwt.WithVerify(alg, &pubkey))
		if !assert.Error(t, err, `jwt.Parse should fail`) {
			return
		}
	})
}

func TestToken(t *testing.T) {
	t1 := jwt.New()
	if !assert.NoError(t, t1.Set(jwt.JwtIDKey, "AbCdEfG"), "setting jti should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.SubjectKey, "foobar@example.com"), "setting sub should work") {
		return
	}

	// Silly fix to remove monotonic element from time.Time obatained
	// from time.Now(). Without this, the equality comparison goes
	// ga-ga for golang tip (1.9)
	now := time.Unix(time.Now().Unix(), 0)
	if !assert.NoError(t, t1.Set(jwt.IssuedAtKey, now.Unix()), "setting iat to now should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.NotBeforeKey, now.Add(5*time.Second)), "setting nbf should work") {
		return
	}
	if !assert.NoError(t, t1.Set(jwt.ExpirationKey, now.Add(10*time.Second).Unix()), "setting exp should work") {
		return
	}
	if !assert.NoError(t, t1.Set("custom", "MyValue"), "setting custom should work") {
		return
	}

	jsonbuf1, err := json.MarshalIndent(t1, "", "  ")
	if !assert.NoError(t, err, "JSON marshal should succeed") {
		return
	}
	t.Logf("%s", jsonbuf1)

	var t2 jwt.Token
	if !assert.NoError(t, json.Unmarshal(jsonbuf1, &t2), "JSON unmarshal should succeed") {
		return
	}

	jsonbuf2, err := json.MarshalIndent(t2, "", "  ")
	if !assert.NoError(t, err, "JSON marshal should succeed") {
		return
	}
	t.Logf("%s", jsonbuf2)

	if !assert.Equal(t, t1, &t2, "tokens match") {
		return
	}
}

func TestGHIssue10(t *testing.T) {
	t.Run(jwt.IssuerKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.IssuerKey, "github.com/lestrrat/go-jwx")

		// This should succeed, because WithIssuer is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "t1.Verify should succeed") {
			return
		}

		// This should succeed, because WithIssuer is provided with same value
		if !assert.NoError(t, t1.Verify(jwt.WithIssuer(t1.Issuer())), "t1.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithIssuer("poop")), "t1.Verify should fail") {
			return
		}
	})
	t.Run(jwt.AudienceKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.AudienceKey, []string{
			"foo",
			"bar",
			"baz",
		})

		// This should succeed, because WithAudience is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "token.Verify should succeed") {
			return
		}

		// This should succeed, because WithAudience is provided, and its
		// value matches one of the audience values
		if !assert.NoError(t, t1.Verify(jwt.WithAudience("baz")), "token.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithAudience("poop")), "token.Verify should fail") {
			return
		}
	})
	t.Run(jwt.SubjectKey, func(t *testing.T) {
		t1 := jwt.New()
		t1.Set(jwt.SubjectKey, "github.com/lestrrat/go-jwx")

		// This should succeed, because WithSubject is not provided in the
		// optinal parameters
		if !assert.NoError(t, t1.Verify(), "token.Verify should succeed") {
			return
		}

		// This should succeed, because WithSubject is provided with same value
		if !assert.NoError(t, t1.Verify(jwt.WithSubject(t1.Subject())), "token.Verify should succeed") {
			return
		}

		if !assert.Error(t, t1.Verify(jwt.WithSubject("poop")), "token.Verify should fail") {
			return
		}
	})
	t.Run(jwt.NotBeforeKey, func(t *testing.T) {
		t1 := jwt.New()

		// NotBefore is set to future date
		tm := time.Now().Add(72 * time.Hour)
		t1.Set(jwt.NotBeforeKey, tm)

		// This should fail, because nbf is the future
		if !assert.Error(t, t1.Verify(), "token.Verify should fail") {
			return
		}

		// This should succeed, because we have given reaaaaaaly big skew
		// that is well enough to get us accepted
		if !assert.NoError(t, t1.Verify(jwt.WithAcceptableSkew(73*time.Hour)), "token.Verify should succeed") {
			return
		}

		// This should succeed, because we have given a time
		// that is well enough into the future
		if !assert.NoError(t, t1.Verify(jwt.WithClock(jwt.ClockFunc(func() time.Time { return tm.Add(time.Hour) }))), "token.Verify should succeed") {
			return
		}
	})
	t.Run(jwt.ExpirationKey, func(t *testing.T) {
		t1 := jwt.New()

		// issuedat = 1 Hr before current time
		tm := time.Now()
		t1.Set(jwt.IssuedAtKey, tm.Add(-1*time.Hour))

		// valid for 2 minutes only from IssuedAt
		t1.Set(jwt.ExpirationKey, tm.Add(-58*time.Minute))

		// This should fail, because exp is set in the past
		if !assert.Error(t, t1.Verify(), "token.Verify should fail") {
			return
		}

		// This should succeed, because we have given big skew
		// that is well enough to get us accepted
		if !assert.NoError(t, t1.Verify(jwt.WithAcceptableSkew(time.Hour)), "token.Verify should succeed (1)") {
			return
		}

		// This should succeed, because we have given a time
		// that is well enough into the past
		clock := jwt.ClockFunc(func() time.Time {
			return tm.Add(-59 * time.Minute)
		})
		if !assert.NoError(t, t1.Verify(jwt.WithClock(clock)), "token.Verify should succeed (2)") {
			return
		}
	})
}

func TestVerifyClaims(t *testing.T) {
	// GitHub issue #37: tokens are invalid in the second they are created (because Now() is not after IssuedAt())
	t.Run(jwt.IssuedAtKey+"+skew", func(t *testing.T) {
		token := jwt.New()
		now := time.Now().UTC()
		token.Set(jwt.IssuedAtKey, now)

		const DefaultSkew = 0

		args := []jwt.Option{
			jwt.WithClock(jwt.ClockFunc(func() time.Time { return now })),
			jwt.WithAcceptableSkew(DefaultSkew),
		}

		if !assert.NoError(t, token.Verify(args...), "token.Verify should validate tokens in the same second they are created") {
			if now.Equal(token.IssuedAt()) {
				t.Errorf("iat claim failed: iat == now")
			}
			return
		}
	})
}

const aLongLongTimeAgo = 233431200
const aLongLongTimeAgoString = "233431200"

func TestUnmarshal(t *testing.T) {
	testcases := []struct {
		Title    string
		JSON     string
		Expected func() *jwt.Token
	}{
		{
			Title: "single aud",
			JSON:  `{"aud":"foo"}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set("aud", "foo")
				return t
			},
		},
		{
			Title: "multiple aud's",
			JSON:  `{"aud":["foo","bar"]}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set("aud", []string{"foo", "bar"})
				return t
			},
		},
		{
			Title: "issuedAt",
			JSON:  `{"` + jwt.IssuedAtKey + `":` + aLongLongTimeAgoString + `}`,
			Expected: func() *jwt.Token {
				t := jwt.New()
				t.Set(jwt.IssuedAtKey, aLongLongTimeAgo)
				return t
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.Title, func(t *testing.T) {
			var token jwt.Token
			if !assert.NoError(t, json.Unmarshal([]byte(tc.JSON), &token), `json.Unmarshal should succeed`) {
				return
			}
			if !assert.Equal(t, tc.Expected(), &token, `token should match expeted value`) {
				return
			}

			var buf bytes.Buffer
			if !assert.NoError(t, json.NewEncoder(&buf).Encode(token), `json.Marshal should succeed`) {
				return
			}
			if !assert.Equal(t, tc.JSON, strings.TrimSpace(buf.String()), `json should match`) {
				return
			}
		})
	}
}

func TestGet(t *testing.T) {
	testcases := []struct {
		Title string
		Test  func(*testing.T, *jwt.Token)
		Token func() *jwt.Token
	}{
		{
			Title: `Get IssuedAt`,
			Test: func(t *testing.T, token *jwt.Token) {
				expected := time.Unix(aLongLongTimeAgo, 0).UTC()
				if !assert.Equal(t, expected, token.IssuedAt(), `IssuedAt should match`) {
					return
				}
			},
			Token: func() *jwt.Token {
				t := jwt.New()
				t.Set(jwt.IssuedAtKey, 233431200)
				return t
			},
		},
	}

	for _, tc := range testcases {
		t.Run(tc.Title, func(t *testing.T) {
			tc.Test(t, tc.Token())
		})
	}
}
<|endoftext|>


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

// Package fileutil contains code to work with shell files, also known
// as shell scripts.
package fileutil

import (
	"os"
	"regexp"
	"strings"
)

var (
	shebangRe = regexp.MustCompile(`^#!\s?/(usr/)?bin/(env\s+)?(sh|bash)\s`)
	extRe     = regexp.MustCompile(`\.(sh|bash)$`)
)

func HasShebang(bs []byte) bool {
	return shebangRe.Match(bs)
}

type ScriptConfidence int

const (
	ConfNotScript ScriptConfidence = iota
	ConfIfShebang
	ConfIsScript
)

func CouldBeScript(info os.FileInfo) ScriptConfidence {
	name := info.Name()
	switch {
	case info.IsDir(), name[0] == '.', !info.Mode().IsRegular():
		return ConfNotScript
	case extRe.MatchString(name):
		return ConfIsScript
	case strings.Contains(name, "."):
		return ConfNotScript // different extension
	case info.Size() < int64(len("#/bin/sh\n")):
		return ConfNotScript // cannot possibly hold valid shebang
	default:
		return ConfIfShebang
	}
}
<commit_msg>fileutil: add godoc to exported names<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

// Package fileutil contains code to work with shell files, also known
// as shell scripts.
package fileutil

import (
	"os"
	"regexp"
	"strings"
)

var (
	shebangRe = regexp.MustCompile(`^#!\s?/(usr/)?bin/(env\s+)?(sh|bash)\s`)
	extRe     = regexp.MustCompile(`\.(sh|bash)$`)
)

// HasShebang reports whether bs begins with a valid sh or bash shebang.
// It supports variations with /usr and env.
func HasShebang(bs []byte) bool {
	return shebangRe.Match(bs)
}

// ScriptConfidence defines how likely a file is to be a shell script,
// from complete certainty that it is not one to complete certainty that
// it is one.
type ScriptConfidence int

const (
	ConfNotScript ScriptConfidence = iota
	ConfIfShebang
	ConfIsScript
)

// CouldBeScript reports how likely a file is to be a shell script.
func CouldBeScript(info os.FileInfo) ScriptConfidence {
	name := info.Name()
	switch {
	case info.IsDir(), name[0] == '.', !info.Mode().IsRegular():
		return ConfNotScript
	case extRe.MatchString(name):
		return ConfIsScript
	case strings.Contains(name, "."):
		return ConfNotScript // different extension
	case info.Size() < int64(len("#/bin/sh\n")):
		return ConfNotScript // cannot possibly hold valid shebang
	default:
		return ConfIfShebang
	}
}
<|endoftext|>


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

package restorable

import (
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/sync"
)

// restoringEnabled indicates if restoring happens or not.
//
// This value is overridden at enabled_*.go.
var restoringEnabled = true

// IsRestoringEnabled returns a boolean value indicating whether
// restoring process works or not.
func IsRestoringEnabled() bool {
	// This value is updated only at init or EnableRestoringForTesting.
	// No need to lock here.
	return restoringEnabled
}

// EnableRestoringForTesting forces to enable restoring for testing.
func EnableRestoringForTesting() {
	restoringEnabled = true
}

// images is a set of Image objects.
type images struct {
	images     map[*Image]struct{}
	lastTarget *Image
	m          sync.Mutex
}

// theImages represents the images for the current process.
var theImages = &images{
	images: map[*Image]struct{}{},
}

// ResolveStaleImages flushes the queued draw commands and resolves
// all stale images.
//
// ResolveStaleImages is intended to be called at the end of a frame.
func ResolveStaleImages() error {
	if err := graphics.FlushCommands(); err != nil {
		return err
	}
	if !restoringEnabled {
		return nil
	}
	return theImages.resolveStaleImages()
}

// Restore restores the images.
//
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
func Restore() error {
	if err := graphics.ResetGLState(); err != nil {
		return err
	}
	return theImages.restore()
}

// add adds img to the images.
func (i *images) add(img *Image) {
	i.m.Lock()
	defer i.m.Unlock()
	i.images[img] = struct{}{}
}

// remove removes img from the images.
func (i *images) remove(img *Image) {
	i.m.Lock()
	defer i.m.Unlock()
	delete(i.images, img)
}

// resolveStaleImages resolves stale images.
func (i *images) resolveStaleImages() error {
	i.m.Lock()
	defer i.m.Unlock()
	i.lastTarget = nil
	for img := range i.images {
		if err := img.resolveStale(); err != nil {
			return err
		}
	}
	return nil
}

// makeStaleIfDependingOn makes all the images stale that depend on target.
//
// When target is changed, all images depending on target can't be restored with target.
// makeStaleIfDependingOn is called in such situation.
func (i *images) makeStaleIfDependingOn(target *Image) {
	// Avoid defer for performance
	i.m.Lock()
	if target == nil {
		// disposed
		i.m.Unlock()
		return
	}
	if i.lastTarget == target {
		i.m.Unlock()
		return
	}
	i.lastTarget = target
	for img := range i.images {
		// TODO: This seems not enough: What if img becomes stale but what about
		// other images depend on img? (#357)
		img.makeStaleIfDependingOn(target)
	}
	i.m.Unlock()
}

// restore restores the images.
//
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
func (i *images) restore() error {
	i.m.Lock()
	defer i.m.Unlock()
	if !IsRestoringEnabled() {
		panic("not reached")
	}

	// Framebuffers/textures cannot be disposed since framebuffers/textures that
	// don't belong to the current context.

	// Let's do topological sort based on dependencies of drawing history.
	// It is assured that there are not loops since cyclic drawing makes images stale.
	type edge struct {
		source *Image
		target *Image
	}
	images := map[*Image]struct{}{}
	for i := range i.images {
		images[i] = struct{}{}
	}
	edges := map[edge]struct{}{}
	for t := range images {
		for s := range t.dependingImages() {
			edges[edge{source: s, target: t}] = struct{}{}
		}
	}
	sorted := []*Image{}
	for len(images) > 0 {
		// current repesents images that have no incoming edges.
		current := map[*Image]struct{}{}
		for i := range images {
			current[i] = struct{}{}
		}
		for e := range edges {
			if _, ok := current[e.target]; ok {
				delete(current, e.target)
			}
		}
		for i := range current {
			delete(images, i)
			sorted = append(sorted, i)
		}
		removed := []edge{}
		for e := range edges {
			if _, ok := current[e.source]; ok {
				removed = append(removed, e)
			}
		}
		for _, e := range removed {
			delete(edges, e)
		}
	}
	for _, img := range sorted {
		if err := img.restore(); err != nil {
			return err
		}
	}
	return nil
}

// InitializeGLState initializes the GL state.
func InitializeGLState() error {
	return graphics.ResetGLState()
}
<commit_msg>restorable: Ensure the given image is not nil at makeStaleIfDependingOn<commit_after>// Copyright 2017 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package restorable

import (
	"github.com/hajimehoshi/ebiten/internal/graphics"
	"github.com/hajimehoshi/ebiten/internal/sync"
)

// restoringEnabled indicates if restoring happens or not.
//
// This value is overridden at enabled_*.go.
var restoringEnabled = true

// IsRestoringEnabled returns a boolean value indicating whether
// restoring process works or not.
func IsRestoringEnabled() bool {
	// This value is updated only at init or EnableRestoringForTesting.
	// No need to lock here.
	return restoringEnabled
}

// EnableRestoringForTesting forces to enable restoring for testing.
func EnableRestoringForTesting() {
	restoringEnabled = true
}

// images is a set of Image objects.
type images struct {
	images     map[*Image]struct{}
	lastTarget *Image
	m          sync.Mutex
}

// theImages represents the images for the current process.
var theImages = &images{
	images: map[*Image]struct{}{},
}

// ResolveStaleImages flushes the queued draw commands and resolves
// all stale images.
//
// ResolveStaleImages is intended to be called at the end of a frame.
func ResolveStaleImages() error {
	if err := graphics.FlushCommands(); err != nil {
		return err
	}
	if !restoringEnabled {
		return nil
	}
	return theImages.resolveStaleImages()
}

// Restore restores the images.
//
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
func Restore() error {
	if err := graphics.ResetGLState(); err != nil {
		return err
	}
	return theImages.restore()
}

// add adds img to the images.
func (i *images) add(img *Image) {
	i.m.Lock()
	defer i.m.Unlock()
	i.images[img] = struct{}{}
}

// remove removes img from the images.
func (i *images) remove(img *Image) {
	i.m.Lock()
	defer i.m.Unlock()
	delete(i.images, img)
}

// resolveStaleImages resolves stale images.
func (i *images) resolveStaleImages() error {
	i.m.Lock()
	defer i.m.Unlock()
	i.lastTarget = nil
	for img := range i.images {
		if err := img.resolveStale(); err != nil {
			return err
		}
	}
	return nil
}

// makeStaleIfDependingOn makes all the images stale that depend on target.
//
// When target is changed, all images depending on target can't be restored with target.
// makeStaleIfDependingOn is called in such situation.
func (i *images) makeStaleIfDependingOn(target *Image) {
	if target == nil {
		panic("not reached")
	}
	// Avoid defer for performance
	i.m.Lock()
	if i.lastTarget == target {
		i.m.Unlock()
		return
	}
	i.lastTarget = target
	for img := range i.images {
		// TODO: This seems not enough: What if img becomes stale but what about
		// other images depend on img? (#357)
		img.makeStaleIfDependingOn(target)
	}
	i.m.Unlock()
}

// restore restores the images.
//
// Restoring means to make all *graphics.Image objects have their textures and framebuffers.
func (i *images) restore() error {
	i.m.Lock()
	defer i.m.Unlock()
	if !IsRestoringEnabled() {
		panic("not reached")
	}

	// Framebuffers/textures cannot be disposed since framebuffers/textures that
	// don't belong to the current context.

	// Let's do topological sort based on dependencies of drawing history.
	// It is assured that there are not loops since cyclic drawing makes images stale.
	type edge struct {
		source *Image
		target *Image
	}
	images := map[*Image]struct{}{}
	for i := range i.images {
		images[i] = struct{}{}
	}
	edges := map[edge]struct{}{}
	for t := range images {
		for s := range t.dependingImages() {
			edges[edge{source: s, target: t}] = struct{}{}
		}
	}
	sorted := []*Image{}
	for len(images) > 0 {
		// current repesents images that have no incoming edges.
		current := map[*Image]struct{}{}
		for i := range images {
			current[i] = struct{}{}
		}
		for e := range edges {
			if _, ok := current[e.target]; ok {
				delete(current, e.target)
			}
		}
		for i := range current {
			delete(images, i)
			sorted = append(sorted, i)
		}
		removed := []edge{}
		for e := range edges {
			if _, ok := current[e.source]; ok {
				removed = append(removed, e)
			}
		}
		for _, e := range removed {
			delete(edges, e)
		}
	}
	for _, img := range sorted {
		if err := img.restore(); err != nil {
			return err
		}
	}
	return nil
}

// InitializeGLState initializes the GL state.
func InitializeGLState() error {
	return graphics.ResetGLState()
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package js

import (
	"unicode"

	"github.com/gopherjs/gopherwasm/js"

	"github.com/hajimehoshi/ebiten/internal/driver"
)

type pos struct {
	X int
	Y int
}

type gamePad struct {
	valid         bool
	axisNum       int
	axes          [16]float64
	buttonNum     int
	buttonPressed [256]bool
}

type Input struct {
	keyPressed         map[string]bool
	keyPressedEdge     map[int]bool
	mouseButtonPressed map[int]bool
	cursorX            int
	cursorY            int
	wheelX             float64
	wheelY             float64
	gamepads           [16]gamePad
	touches            map[int]pos
	runeBuffer         []rune
	ui                 *UserInterface
}

func (i *Input) CursorPosition() (x, y int) {
	return i.ui.adjustPosition(i.cursorX, i.cursorY)
}

func (i *Input) GamepadIDs() []int {
	if len(i.gamepads) == 0 {
		return nil
	}
	r := []int{}
	for id, g := range i.gamepads {
		if g.valid {
			r = append(r, id)
		}
	}
	return r
}

func (i *Input) GamepadAxisNum(id int) int {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].axisNum
}

func (i *Input) GamepadAxis(id int, axis int) float64 {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].axes[axis]
}

func (i *Input) GamepadButtonNum(id int) int {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].buttonNum
}

func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool {
	if len(i.gamepads) <= id {
		return false
	}
	return i.gamepads[id].buttonPressed[button]
}

func (i *Input) TouchIDs() []int {
	if len(i.touches) == 0 {
		return nil
	}

	var ids []int
	for id := range i.touches {
		ids = append(ids, id)
	}
	return ids
}

func (i *Input) TouchPosition(id int) (x, y int) {
	for tid, pos := range i.touches {
		if id == tid {
			return i.ui.adjustPosition(pos.X, pos.Y)
		}
	}
	return 0, 0
}

func (i *Input) RuneBuffer() []rune {
	return i.runeBuffer
}

func (i *Input) ResetForFrame() {
	i.runeBuffer = nil
	i.wheelX = 0
	i.wheelY = 0
}

func (i *Input) IsKeyPressed(key driver.Key) bool {
	if i.keyPressed != nil {
		for _, c := range keyToCodes[key] {
			if i.keyPressed[c] {
				return true
			}
		}
	}
	if i.keyPressedEdge != nil {
		for c, k := range keyCodeToKeyEdge {
			if k != key {
				continue
			}
			if i.keyPressedEdge[c] {
				return true
			}
		}
	}
	return false
}

var codeToMouseButton = map[int]driver.MouseButton{
	0: driver.MouseButtonLeft,
	1: driver.MouseButtonMiddle,
	2: driver.MouseButtonRight,
}

func (i *Input) IsMouseButtonPressed(button driver.MouseButton) bool {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	for c, b := range codeToMouseButton {
		if b != button {
			continue
		}
		if i.mouseButtonPressed[c] {
			return true
		}
	}
	return false
}

func (i *Input) Wheel() (xoff, yoff float64) {
	return i.wheelX, i.wheelY
}

func (i *Input) keyDown(code string) {
	if i.keyPressed == nil {
		i.keyPressed = map[string]bool{}
	}
	i.keyPressed[code] = true
}

func (i *Input) keyUp(code string) {
	if i.keyPressed == nil {
		i.keyPressed = map[string]bool{}
	}
	i.keyPressed[code] = false
}

func (i *Input) keyDownEdge(code int) {
	if i.keyPressedEdge == nil {
		i.keyPressedEdge = map[int]bool{}
	}
	i.keyPressedEdge[code] = true
}

func (i *Input) keyUpEdge(code int) {
	if i.keyPressedEdge == nil {
		i.keyPressedEdge = map[int]bool{}
	}
	i.keyPressedEdge[code] = false
}

func (i *Input) mouseDown(code int) {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	i.mouseButtonPressed[code] = true
}

func (i *Input) mouseUp(code int) {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	i.mouseButtonPressed[code] = false
}

func (i *Input) setMouseCursor(x, y int) {
	i.cursorX, i.cursorY = x, y
}

func (i *Input) UpdateGamepads() {
	nav := js.Global().Get("navigator")
	if nav.Get("getGamepads") == js.Undefined() {
		return
	}
	gamepads := nav.Call("getGamepads")
	l := gamepads.Get("length").Int()
	for id := 0; id < l; id++ {
		i.gamepads[id].valid = false
		gamepad := gamepads.Index(id)
		if gamepad == js.Undefined() || gamepad == js.Null() {
			continue
		}
		i.gamepads[id].valid = true

		axes := gamepad.Get("axes")
		axesNum := axes.Get("length").Int()
		i.gamepads[id].axisNum = axesNum
		for a := 0; a < len(i.gamepads[id].axes); a++ {
			if axesNum <= a {
				i.gamepads[id].axes[a] = 0
				continue
			}
			i.gamepads[id].axes[a] = axes.Index(a).Float()
		}

		buttons := gamepad.Get("buttons")
		buttonsNum := buttons.Get("length").Int()
		i.gamepads[id].buttonNum = buttonsNum
		for b := 0; b < len(i.gamepads[id].buttonPressed); b++ {
			if buttonsNum <= b {
				i.gamepads[id].buttonPressed[b] = false
				continue
			}
			i.gamepads[id].buttonPressed[b] = buttons.Index(b).Get("pressed").Bool()
		}
	}
}

func (i *Input) Update(e js.Value) {
	switch e.Get("type").String() {
	case "keydown":
		c := e.Get("code")
		if c == js.Undefined() {
			code := e.Get("keyCode").Int()
			if keyCodeToKeyEdge[code] == driver.KeyUp ||
				keyCodeToKeyEdge[code] == driver.KeyDown ||
				keyCodeToKeyEdge[code] == driver.KeyLeft ||
				keyCodeToKeyEdge[code] == driver.KeyRight ||
				keyCodeToKeyEdge[code] == driver.KeyBackspace ||
				keyCodeToKeyEdge[code] == driver.KeyTab {
				e.Call("preventDefault")
			}
			i.keyDownEdge(code)
			return
		}
		cs := c.String()
		if cs == keyToCodes[driver.KeyUp][0] ||
			cs == keyToCodes[driver.KeyDown][0] ||
			cs == keyToCodes[driver.KeyLeft][0] ||
			cs == keyToCodes[driver.KeyRight][0] ||
			cs == keyToCodes[driver.KeyBackspace][0] ||
			cs == keyToCodes[driver.KeyTab][0] {
			e.Call("preventDefault")
		}
		i.keyDown(cs)
	case "keypress":
		if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) {
			i.runeBuffer = append(i.runeBuffer, r)
		}
	case "keyup":
		if e.Get("code") == js.Undefined() {
			// Assume that UA is Edge.
			code := e.Get("keyCode").Int()
			i.keyUpEdge(code)
			return
		}
		code := e.Get("code").String()
		i.keyUp(code)
	case "mousedown":
		button := e.Get("button").Int()
		i.mouseDown(button)
		i.setMouseCursorFromEvent(e)
	case "mouseup":
		button := e.Get("button").Int()
		i.mouseUp(button)
		i.setMouseCursorFromEvent(e)
	case "mousemove":
		i.setMouseCursorFromEvent(e)
	case "wheel":
		// TODO: What if e.deltaMode is not DOM_DELTA_PIXEL?
		i.wheelX = -e.Get("deltaX").Float()
		i.wheelY = -e.Get("deltaY").Float()
	case "touchstart", "touchend", "touchmove":
		i.updateTouches(e)
	}
}

func (i *Input) setMouseCursorFromEvent(e js.Value) {
	x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
	i.setMouseCursor(x, y)
}

func (i *Input) updateTouches(e js.Value) {
	j := e.Get("targetTouches")
	ts := map[int]pos{}
	for i := 0; i < len(ts); i++ {
		jj := j.Call("item", i)
		id := jj.Get("identifier").Int()
		ts[id] = pos{
			X: jj.Get("clientX").Int(),
			Y: jj.Get("clientY").Int(),
		}
	}
	i.touches = ts
}
<commit_msg>uidriver/js: Bug fix: Touches were not updated correctly<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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.

// +build js

package js

import (
	"unicode"

	"github.com/gopherjs/gopherwasm/js"

	"github.com/hajimehoshi/ebiten/internal/driver"
)

type pos struct {
	X int
	Y int
}

type gamePad struct {
	valid         bool
	axisNum       int
	axes          [16]float64
	buttonNum     int
	buttonPressed [256]bool
}

type Input struct {
	keyPressed         map[string]bool
	keyPressedEdge     map[int]bool
	mouseButtonPressed map[int]bool
	cursorX            int
	cursorY            int
	wheelX             float64
	wheelY             float64
	gamepads           [16]gamePad
	touches            map[int]pos
	runeBuffer         []rune
	ui                 *UserInterface
}

func (i *Input) CursorPosition() (x, y int) {
	return i.ui.adjustPosition(i.cursorX, i.cursorY)
}

func (i *Input) GamepadIDs() []int {
	if len(i.gamepads) == 0 {
		return nil
	}
	r := []int{}
	for id, g := range i.gamepads {
		if g.valid {
			r = append(r, id)
		}
	}
	return r
}

func (i *Input) GamepadAxisNum(id int) int {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].axisNum
}

func (i *Input) GamepadAxis(id int, axis int) float64 {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].axes[axis]
}

func (i *Input) GamepadButtonNum(id int) int {
	if len(i.gamepads) <= id {
		return 0
	}
	return i.gamepads[id].buttonNum
}

func (i *Input) IsGamepadButtonPressed(id int, button driver.GamepadButton) bool {
	if len(i.gamepads) <= id {
		return false
	}
	return i.gamepads[id].buttonPressed[button]
}

func (i *Input) TouchIDs() []int {
	if len(i.touches) == 0 {
		return nil
	}

	var ids []int
	for id := range i.touches {
		ids = append(ids, id)
	}
	return ids
}

func (i *Input) TouchPosition(id int) (x, y int) {
	for tid, pos := range i.touches {
		if id == tid {
			return i.ui.adjustPosition(pos.X, pos.Y)
		}
	}
	return 0, 0
}

func (i *Input) RuneBuffer() []rune {
	return i.runeBuffer
}

func (i *Input) ResetForFrame() {
	i.runeBuffer = nil
	i.wheelX = 0
	i.wheelY = 0
}

func (i *Input) IsKeyPressed(key driver.Key) bool {
	if i.keyPressed != nil {
		for _, c := range keyToCodes[key] {
			if i.keyPressed[c] {
				return true
			}
		}
	}
	if i.keyPressedEdge != nil {
		for c, k := range keyCodeToKeyEdge {
			if k != key {
				continue
			}
			if i.keyPressedEdge[c] {
				return true
			}
		}
	}
	return false
}

var codeToMouseButton = map[int]driver.MouseButton{
	0: driver.MouseButtonLeft,
	1: driver.MouseButtonMiddle,
	2: driver.MouseButtonRight,
}

func (i *Input) IsMouseButtonPressed(button driver.MouseButton) bool {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	for c, b := range codeToMouseButton {
		if b != button {
			continue
		}
		if i.mouseButtonPressed[c] {
			return true
		}
	}
	return false
}

func (i *Input) Wheel() (xoff, yoff float64) {
	return i.wheelX, i.wheelY
}

func (i *Input) keyDown(code string) {
	if i.keyPressed == nil {
		i.keyPressed = map[string]bool{}
	}
	i.keyPressed[code] = true
}

func (i *Input) keyUp(code string) {
	if i.keyPressed == nil {
		i.keyPressed = map[string]bool{}
	}
	i.keyPressed[code] = false
}

func (i *Input) keyDownEdge(code int) {
	if i.keyPressedEdge == nil {
		i.keyPressedEdge = map[int]bool{}
	}
	i.keyPressedEdge[code] = true
}

func (i *Input) keyUpEdge(code int) {
	if i.keyPressedEdge == nil {
		i.keyPressedEdge = map[int]bool{}
	}
	i.keyPressedEdge[code] = false
}

func (i *Input) mouseDown(code int) {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	i.mouseButtonPressed[code] = true
}

func (i *Input) mouseUp(code int) {
	if i.mouseButtonPressed == nil {
		i.mouseButtonPressed = map[int]bool{}
	}
	i.mouseButtonPressed[code] = false
}

func (i *Input) setMouseCursor(x, y int) {
	i.cursorX, i.cursorY = x, y
}

func (i *Input) UpdateGamepads() {
	nav := js.Global().Get("navigator")
	if nav.Get("getGamepads") == js.Undefined() {
		return
	}
	gamepads := nav.Call("getGamepads")
	l := gamepads.Get("length").Int()
	for id := 0; id < l; id++ {
		i.gamepads[id].valid = false
		gamepad := gamepads.Index(id)
		if gamepad == js.Undefined() || gamepad == js.Null() {
			continue
		}
		i.gamepads[id].valid = true

		axes := gamepad.Get("axes")
		axesNum := axes.Get("length").Int()
		i.gamepads[id].axisNum = axesNum
		for a := 0; a < len(i.gamepads[id].axes); a++ {
			if axesNum <= a {
				i.gamepads[id].axes[a] = 0
				continue
			}
			i.gamepads[id].axes[a] = axes.Index(a).Float()
		}

		buttons := gamepad.Get("buttons")
		buttonsNum := buttons.Get("length").Int()
		i.gamepads[id].buttonNum = buttonsNum
		for b := 0; b < len(i.gamepads[id].buttonPressed); b++ {
			if buttonsNum <= b {
				i.gamepads[id].buttonPressed[b] = false
				continue
			}
			i.gamepads[id].buttonPressed[b] = buttons.Index(b).Get("pressed").Bool()
		}
	}
}

func (i *Input) Update(e js.Value) {
	switch e.Get("type").String() {
	case "keydown":
		c := e.Get("code")
		if c == js.Undefined() {
			code := e.Get("keyCode").Int()
			if keyCodeToKeyEdge[code] == driver.KeyUp ||
				keyCodeToKeyEdge[code] == driver.KeyDown ||
				keyCodeToKeyEdge[code] == driver.KeyLeft ||
				keyCodeToKeyEdge[code] == driver.KeyRight ||
				keyCodeToKeyEdge[code] == driver.KeyBackspace ||
				keyCodeToKeyEdge[code] == driver.KeyTab {
				e.Call("preventDefault")
			}
			i.keyDownEdge(code)
			return
		}
		cs := c.String()
		if cs == keyToCodes[driver.KeyUp][0] ||
			cs == keyToCodes[driver.KeyDown][0] ||
			cs == keyToCodes[driver.KeyLeft][0] ||
			cs == keyToCodes[driver.KeyRight][0] ||
			cs == keyToCodes[driver.KeyBackspace][0] ||
			cs == keyToCodes[driver.KeyTab][0] {
			e.Call("preventDefault")
		}
		i.keyDown(cs)
	case "keypress":
		if r := rune(e.Get("charCode").Int()); unicode.IsPrint(r) {
			i.runeBuffer = append(i.runeBuffer, r)
		}
	case "keyup":
		if e.Get("code") == js.Undefined() {
			// Assume that UA is Edge.
			code := e.Get("keyCode").Int()
			i.keyUpEdge(code)
			return
		}
		code := e.Get("code").String()
		i.keyUp(code)
	case "mousedown":
		button := e.Get("button").Int()
		i.mouseDown(button)
		i.setMouseCursorFromEvent(e)
	case "mouseup":
		button := e.Get("button").Int()
		i.mouseUp(button)
		i.setMouseCursorFromEvent(e)
	case "mousemove":
		i.setMouseCursorFromEvent(e)
	case "wheel":
		// TODO: What if e.deltaMode is not DOM_DELTA_PIXEL?
		i.wheelX = -e.Get("deltaX").Float()
		i.wheelY = -e.Get("deltaY").Float()
	case "touchstart", "touchend", "touchmove":
		i.updateTouches(e)
	}
}

func (i *Input) setMouseCursorFromEvent(e js.Value) {
	x, y := e.Get("clientX").Int(), e.Get("clientY").Int()
	i.setMouseCursor(x, y)
}

func (i *Input) updateTouches(e js.Value) {
	j := e.Get("targetTouches")
	ts := map[int]pos{}
	for i := 0; i < j.Length(); i++ {
		jj := j.Call("item", i)
		id := jj.Get("identifier").Int()
		ts[id] = pos{
			X: jj.Get("clientX").Int(),
			Y: jj.Get("clientY").Int(),
		}
	}
	i.touches = ts
}
<|endoftext|>


<commit_before>package dsbldr

// RunFunc holds the computation that processes the API responses to features
// is sent a JSON string of the response ??as well as a map of data from the features parent features??
// Basically what you do with the run function is take in a string of
// serialized API data (could be in JSON or XML), do parsing on your
// own or using utility functions. You do whatever computations you want and
// then spit it back as an array of strings to read to CSV or JSON
type RunFunc func(response string) []string // parents map[string]string

// Structs representing RetreiveType
// SingleRetrieve Features only require one request to create the JSON Dump
// that's passed to the RunFunc
// Repeated Retrieve Features require one request per value-set of
// of parent features that are concatenated into a JSON array and then passed
// to the Features RunFunc
// Almost as a given, all dependent features will be of RepeatedRetrieve per
// value sets of their parent features
const (
	SingleRetrieve = iota
	RepeatedRetrieve
)

// Feature Download statuses
const (
	Ready = iota
	NotReady
)

// Feature in the dataset, on which all other features are based on
type Feature struct {
	Name         string
	Endpoint     string // API Endpoint
	RunFunc      RunFunc
	RetrieveType int // Determines if multiple or single requests are made to the api
	noSave       bool
	status       chan int // download status of feature
}

// NewFeature creates new Feature with defaults
func NewFeature() *Feature {
	return &Feature{
		noSave: false,
	}
}
<commit_msg>Preallocate Feature.status in NewFeature<commit_after>package dsbldr

// RunFunc holds the computation that processes the API responses to features
// is sent a JSON string of the response ??as well as a map of data from the features parent features??
// Basically what you do with the run function is take in a string of
// serialized API data (could be in JSON or XML), do parsing on your
// own or using utility functions. You do whatever computations you want and
// then spit it back as an array of strings to read to CSV or JSON
type RunFunc func(response string) []string // parents map[string]string

// Structs representing RetreiveType
// SingleRetrieve Features only require one request to create the JSON Dump
// that's passed to the RunFunc
// Repeated Retrieve Features require one request per value-set of
// of parent features that are concatenated into a JSON array and then passed
// to the Features RunFunc
// Almost as a given, all dependent features will be of RepeatedRetrieve per
// value sets of their parent features
const (
	SingleRetrieve = iota
	RepeatedRetrieve
)

// Feature Download statuses
const (
	Ready = iota
	NotReady
)

// Feature in the dataset, on which all other features are based on
type Feature struct {
	Name         string
	Endpoint     string // API Endpoint
	RunFunc      RunFunc
	RetrieveType int // Determines if multiple or single requests are made to the api
	noSave       bool
	status       chan int // download status of feature
}

// NewFeature creates new Feature with defaults
func NewFeature() *Feature {
	return &Feature{
		noSave: false,
		status: make(chan int),
	}
}
<|endoftext|>


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

package main

import (
	"fmt"
	"strconv"

	"github.com/couchbase/gomemcached/client"
	log "github.com/couchbaselabs/clog"
	"github.com/couchbaselabs/go-couchbase"
)

type TAPFeed struct {
	name       string
	url        string
	poolName   string
	bucketName string
	bucketUUID string
	pf         StreamPartitionFunc
	streams    map[string]Stream
	closeCh    chan bool
	doneCh     chan bool
	doneErr    error
	doneMsg    string
}

func NewTAPFeed(name, url, poolName, bucketName, bucketUUID string,
	pf StreamPartitionFunc, streams map[string]Stream) (*TAPFeed, error) {
	return &TAPFeed{
		name:       name,
		url:        url,
		poolName:   poolName,
		bucketName: bucketName,
		bucketUUID: bucketUUID,
		pf:         pf,
		streams:    streams,
		closeCh:    make(chan bool),
		doneCh:     make(chan bool),
		doneErr:    nil,
		doneMsg:    "",
	}, nil
}

func (t *TAPFeed) Name() string {
	return t.name
}

func (t *TAPFeed) Start() error {
	log.Printf("TAPFeed.Start, name: %s", t.Name())

	go ExponentialBackoffLoop(t.Name(),
		func() int {
			progress, err := t.feed()
			if err != nil {
				log.Printf("TAPFeed name: %s, progress: %d, err: %v",
					t.Name(), progress, err)
			}
			return progress
		},
		FEED_SLEEP_INIT_MS,  // Milliseconds.
		FEED_BACKOFF_FACTOR, // Backoff.
		FEED_SLEEP_MAX_MS)

	return nil
}

func (t *TAPFeed) feed() (int, error) {
	select {
	case <-t.closeCh:
		t.doneErr = nil
		t.doneMsg = "closeCh closed"
		close(t.doneCh)
		return -1, nil
	default:
	}

	bucket, err := couchbase.GetBucket(t.url, t.poolName, t.bucketName)
	if err != nil {
		return 0, err
	}
	defer bucket.Close()

	if t.bucketUUID != "" && t.bucketUUID != bucket.UUID {
		bucket.Close()
		return -1, fmt.Errorf("error: mismatched bucket uuid,"+
			"bucketName: %s, bucketUUID: %s, bucket.UUID: %s",
			t.bucketName, t.bucketUUID, bucket.UUID)
	}

	args := memcached.TapArguments{}

	vbuckets, err := ParsePartitionsToVBucketIds(t.streams)
	if err != nil {
		return -1, err
	}
	if len(vbuckets) > 0 {
		args.VBuckets = vbuckets
	}

	feed, err := bucket.StartTapFeed(&args)
	if err != nil {
		return 0, err
	}
	defer feed.Close()

	// TODO: maybe TAPFeed should do a rollback to zero if it finds it
	// needs to do a full backfill.
	// TODO: this TAPFeed implementation currently only works against
	// a couchbase cluster that has just a single node.

	log.Printf("TapFeed: running, url: %s,"+
		" poolName: %s, bucketName: %s, vbuckets: %#v",
		t.url, t.poolName, t.bucketName, vbuckets)

loop:
	for {
		select {
		case <-t.closeCh:
			t.doneErr = nil
			t.doneMsg = "closeCh closed"
			close(t.doneCh)
			return -1, nil

		case req, alive := <-feed.C:
			if !alive {
				break loop
			}

			log.Printf("TapFeed: received from url: %s,"+
				" poolName: %s, bucketName: %s, opcode: %s, req: %#v",
				t.url, t.poolName, t.bucketName, req.Opcode, req)

			partition, stream, err :=
				VBucketIdToPartitionStream(t.pf, t.streams, req.VBucket, req.Key)
			if err != nil {
				return 1, err
			}

			if req.Opcode == memcached.TapMutation {
				stream <- &StreamRequest{
					Op:        STREAM_OP_UPDATE,
					Partition: partition,
					Key:       req.Key,
					Val:       req.Value,
				}
			} else if req.Opcode == memcached.TapDeletion {
				stream <- &StreamRequest{
					Op:        STREAM_OP_DELETE,
					Partition: partition,
					Key:       req.Key,
				}
			}
		}
	}

	return 1, nil
}

func (t *TAPFeed) Close() error {
	select {
	case <-t.doneCh:
		return t.doneErr
	default:
	}

	close(t.closeCh)
	<-t.doneCh
	return t.doneErr
}

func (t *TAPFeed) Streams() map[string]Stream {
	return t.streams
}

func ParsePartitionsToVBucketIds(streams map[string]Stream) ([]uint16, error) {
	vbuckets := make([]uint16, 0, len(streams))
	for partition, _ := range streams {
		if partition != "" {
			vbId, err := strconv.Atoi(partition)
			if err != nil {
				return nil, fmt.Errorf("error: could not parse partition: %s, err: %v",
					partition, err)
			}
			vbuckets = append(vbuckets, uint16(vbId))
		}
	}
	return vbuckets, nil
}

func VBucketIdToPartitionStream(pf StreamPartitionFunc,
	streams map[string]Stream, vbucketId uint16, key []byte) (
	partition string, stream Stream, err error) {
	partition = fmt.Sprintf("%d", vbucketId)
	stream, err = pf(key, partition, streams)
	if err != nil {
		return "", nil, fmt.Errorf("error: VBucketIdToPartitionStream,"+
			" partition func, vbucketId: %d, err: %v", vbucketId, err)
	}
	return partition, stream, err
}
<commit_msg>cache the common vbucketId partition strings<commit_after>//  Copyright (c) 2014 Couchbase, Inc.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the
//  License. You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//  Unless required by applicable law or agreed to in writing,
//  software distributed under the License is distributed on an "AS
//  IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
//  express or implied. See the License for the specific language
//  governing permissions and limitations under the License.

package main

import (
	"fmt"
	"strconv"

	"github.com/couchbase/gomemcached/client"
	log "github.com/couchbaselabs/clog"
	"github.com/couchbaselabs/go-couchbase"
)

type TAPFeed struct {
	name       string
	url        string
	poolName   string
	bucketName string
	bucketUUID string
	pf         StreamPartitionFunc
	streams    map[string]Stream
	closeCh    chan bool
	doneCh     chan bool
	doneErr    error
	doneMsg    string
}

func NewTAPFeed(name, url, poolName, bucketName, bucketUUID string,
	pf StreamPartitionFunc, streams map[string]Stream) (*TAPFeed, error) {
	return &TAPFeed{
		name:       name,
		url:        url,
		poolName:   poolName,
		bucketName: bucketName,
		bucketUUID: bucketUUID,
		pf:         pf,
		streams:    streams,
		closeCh:    make(chan bool),
		doneCh:     make(chan bool),
		doneErr:    nil,
		doneMsg:    "",
	}, nil
}

func (t *TAPFeed) Name() string {
	return t.name
}

func (t *TAPFeed) Start() error {
	log.Printf("TAPFeed.Start, name: %s", t.Name())

	go ExponentialBackoffLoop(t.Name(),
		func() int {
			progress, err := t.feed()
			if err != nil {
				log.Printf("TAPFeed name: %s, progress: %d, err: %v",
					t.Name(), progress, err)
			}
			return progress
		},
		FEED_SLEEP_INIT_MS,  // Milliseconds.
		FEED_BACKOFF_FACTOR, // Backoff.
		FEED_SLEEP_MAX_MS)

	return nil
}

func (t *TAPFeed) feed() (int, error) {
	select {
	case <-t.closeCh:
		t.doneErr = nil
		t.doneMsg = "closeCh closed"
		close(t.doneCh)
		return -1, nil
	default:
	}

	bucket, err := couchbase.GetBucket(t.url, t.poolName, t.bucketName)
	if err != nil {
		return 0, err
	}
	defer bucket.Close()

	if t.bucketUUID != "" && t.bucketUUID != bucket.UUID {
		bucket.Close()
		return -1, fmt.Errorf("error: mismatched bucket uuid,"+
			"bucketName: %s, bucketUUID: %s, bucket.UUID: %s",
			t.bucketName, t.bucketUUID, bucket.UUID)
	}

	args := memcached.TapArguments{}

	vbuckets, err := ParsePartitionsToVBucketIds(t.streams)
	if err != nil {
		return -1, err
	}
	if len(vbuckets) > 0 {
		args.VBuckets = vbuckets
	}

	feed, err := bucket.StartTapFeed(&args)
	if err != nil {
		return 0, err
	}
	defer feed.Close()

	// TODO: maybe TAPFeed should do a rollback to zero if it finds it
	// needs to do a full backfill.
	// TODO: this TAPFeed implementation currently only works against
	// a couchbase cluster that has just a single node.

	log.Printf("TapFeed: running, url: %s,"+
		" poolName: %s, bucketName: %s, vbuckets: %#v",
		t.url, t.poolName, t.bucketName, vbuckets)

loop:
	for {
		select {
		case <-t.closeCh:
			t.doneErr = nil
			t.doneMsg = "closeCh closed"
			close(t.doneCh)
			return -1, nil

		case req, alive := <-feed.C:
			if !alive {
				break loop
			}

			log.Printf("TapFeed: received from url: %s,"+
				" poolName: %s, bucketName: %s, opcode: %s, req: %#v",
				t.url, t.poolName, t.bucketName, req.Opcode, req)

			partition, stream, err :=
				VBucketIdToPartitionStream(t.pf, t.streams, req.VBucket, req.Key)
			if err != nil {
				return 1, err
			}

			if req.Opcode == memcached.TapMutation {
				stream <- &StreamRequest{
					Op:        STREAM_OP_UPDATE,
					Partition: partition,
					Key:       req.Key,
					Val:       req.Value,
				}
			} else if req.Opcode == memcached.TapDeletion {
				stream <- &StreamRequest{
					Op:        STREAM_OP_DELETE,
					Partition: partition,
					Key:       req.Key,
				}
			}
		}
	}

	return 1, nil
}

func (t *TAPFeed) Close() error {
	select {
	case <-t.doneCh:
		return t.doneErr
	default:
	}

	close(t.closeCh)
	<-t.doneCh
	return t.doneErr
}

func (t *TAPFeed) Streams() map[string]Stream {
	return t.streams
}

func ParsePartitionsToVBucketIds(streams map[string]Stream) ([]uint16, error) {
	vbuckets := make([]uint16, 0, len(streams))
	for partition, _ := range streams {
		if partition != "" {
			vbId, err := strconv.Atoi(partition)
			if err != nil {
				return nil, fmt.Errorf("error: could not parse partition: %s, err: %v",
					partition, err)
			}
			vbuckets = append(vbuckets, uint16(vbId))
		}
	}
	return vbuckets, nil
}

func VBucketIdToPartitionStream(pf StreamPartitionFunc,
	streams map[string]Stream, vbucketId uint16, key []byte) (
	partition string, stream Stream, err error) {
	if vbucketId < uint16(len(vbucketIdStrings)) {
		partition = vbucketIdStrings[vbucketId]
	}
	if partition == "" {
		partition = fmt.Sprintf("%d", vbucketId)
	}
	stream, err = pf(key, partition, streams)
	if err != nil {
		return "", nil, fmt.Errorf("error: VBucketIdToPartitionStream,"+
			" partition func, vbucketId: %d, err: %v", vbucketId, err)
	}
	return partition, stream, err
}

var vbucketIdStrings []string

func init() {
	vbucketIdStrings = make([]string, 1024)
	for i := 0; i < len(vbucketIdStrings); i++ {
		vbucketIdStrings[i] = fmt.Sprintf("%d", i)
	}
}
<|endoftext|>


<commit_before>package ud859

import (
	"golang.org/x/net/context"

	"google.golang.org/appengine/datastore"
)

func (p *Profile) register(safeKey string) {
	p.Conferences = append(p.Conferences, safeKey)
}

func (p *Profile) unRegister(safeKey string) {
	for i, key := range p.Conferences {
		if key == safeKey {
			p.Conferences = append(p.Conferences[:i], p.Conferences[i+1:]...)
			break
		}
	}
}

// HasRegistered returns true if the user has registered to the specified conference key.
func (p Profile) HasRegistered(safeKey string) bool {
	for _, key := range p.Conferences {
		if key == safeKey {
			return true
		}
	}
	return false
}

// GotoConference performs the registration to the specified conference.
func (ConferenceAPI) GotoConference(c context.Context, form *ConferenceKeyForm) error {
	pid, err := profileID(c)
	if err != nil {
		return err
	}
	ckey, err := datastore.DecodeKey(form.WebsafeKey)
	if err != nil {
		return errBadRequest(err, "invalid conference key")
	}

	return datastore.RunInTransaction(c, func(c context.Context) error {
		// get the profile
		profile, err := getProfile(c, pid)
		if err != nil {
			return err
		}

		// get the conference
		conference, err := getConference(c, ckey)
		if err != nil {
			return errBadRequest(err, "conference does not exist")
		}

		if profile.HasRegistered(conference.WebsafeKey) {
			return ErrRegistered
		}
		if conference.SeatsAvailable <= 0 {
			return ErrNoSeatsAvailable
		}

		// register to the conference
		profile.register(conference.WebsafeKey)
		_, err = datastore.Put(c, pid.key, profile)
		if err != nil {
			return err
		}

		// decrease the available seats
		conference.SeatsAvailable--
		_, err = datastore.Put(c, ckey, conference)
		return err

	}, &datastore.TransactionOptions{XG: true})
}

// CancelConference cancels the registration to the specified conference.
func (ConferenceAPI) CancelConference(c context.Context, form *ConferenceKeyForm) error {
	pid, err := profileID(c)
	if err != nil {
		return err
	}
	ckey, err := datastore.DecodeKey(form.WebsafeKey)
	if err != nil {
		return errBadRequest(err, "invalid conference key")
	}

	return datastore.RunInTransaction(c, func(c context.Context) error {
		// get the profile
		profile, err := getProfile(c, pid)
		if err != nil {
			return err
		}

		// get the conference
		conference, err := getConference(c, ckey)
		if err != nil {
			return errBadRequest(err, "conference does not exist")
		}

		if !profile.HasRegistered(conference.WebsafeKey) {
			return ErrNotRegistered
		}

		// unregister from the conference
		profile.unRegister(conference.WebsafeKey)
		_, err = datastore.Put(c, pid.key, profile)
		if err != nil {
			return err
		}

		// increase the available seats
		conference.SeatsAvailable++
		_, err = datastore.Put(c, ckey, conference)
		return err

	}, &datastore.TransactionOptions{XG: true})
}
<commit_msg>a bit of concurrency<commit_after>package ud859

import (
	"golang.org/x/net/context"

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
)

func (p *Profile) register(safeKey string) {
	p.Conferences = append(p.Conferences, safeKey)
}

func (p *Profile) unRegister(safeKey string) {
	for i, key := range p.Conferences {
		if key == safeKey {
			p.Conferences = append(p.Conferences[:i], p.Conferences[i+1:]...)
			break
		}
	}
}

// HasRegistered returns true if the user has registered to the specified conference key.
func (p Profile) HasRegistered(safeKey string) bool {
	for _, key := range p.Conferences {
		if key == safeKey {
			return true
		}
	}
	return false
}

// GotoConference performs the registration to the specified conference.
func (ConferenceAPI) GotoConference(c context.Context, form *ConferenceKeyForm) error {
	pid, err := profileID(c)
	if err != nil {
		return err
	}
	ckey, err := datastore.DecodeKey(form.WebsafeKey)
	if err != nil {
		return errBadRequest(err, "invalid conference key")
	}

	return datastore.RunInTransaction(c, func(c context.Context) error {
		errc := make(chan error)
		var profile *Profile
		var conference *Conference

		go func() {
			// get the profile
			var err error
			profile, err = getProfile(c, pid)
			errc <- err
		}()

		go func() {
			// get the conference
			var err error
			conference, err = getConference(c, ckey)
			if err != nil {
				err = errBadRequest(err, "conference does not exist")
			}
			errc <- err
		}()

		// wait and check for errors
		multi := make(appengine.MultiError, 0, 2)
		for i := 0; i < 2; i++ {
			if err := <-errc; err != nil {
				multi = append(multi, err)
			}
		}
		if len(multi) > 0 {
			return multi
		}

		if profile.HasRegistered(conference.WebsafeKey) {
			return ErrRegistered
		}
		if conference.SeatsAvailable <= 0 {
			return ErrNoSeatsAvailable
		}

		// register to the conference
		profile.register(conference.WebsafeKey)
		_, err = datastore.Put(c, pid.key, profile)
		if err != nil {
			return err
		}

		// decrease the available seats
		conference.SeatsAvailable--
		_, err = datastore.Put(c, ckey, conference)
		return err

	}, &datastore.TransactionOptions{XG: true})
}

// CancelConference cancels the registration to the specified conference.
func (ConferenceAPI) CancelConference(c context.Context, form *ConferenceKeyForm) error {
	pid, err := profileID(c)
	if err != nil {
		return err
	}
	ckey, err := datastore.DecodeKey(form.WebsafeKey)
	if err != nil {
		return errBadRequest(err, "invalid conference key")
	}

	return datastore.RunInTransaction(c, func(c context.Context) error {
		errc := make(chan error)
		var profile *Profile
		var conference *Conference

		go func() {
			// get the profile
			var err error
			profile, err = getProfile(c, pid)
			errc <- err
		}()

		go func() {
			// get the conference
			var err error
			conference, err = getConference(c, ckey)
			if err != nil {
				err = errBadRequest(err, "conference does not exist")
			}
			errc <- err
		}()

		// wait and check for errors
		multi := make(appengine.MultiError, 0, 2)
		for i := 0; i < 2; i++ {
			if err := <-errc; err != nil {
				multi = append(multi, err)
			}
		}
		if len(multi) > 0 {
			return multi
		}

		if !profile.HasRegistered(conference.WebsafeKey) {
			return ErrNotRegistered
		}

		// unregister from the conference
		profile.unRegister(conference.WebsafeKey)
		_, err = datastore.Put(c, pid.key, profile)
		if err != nil {
			return err
		}

		// increase the available seats
		conference.SeatsAvailable++
		_, err = datastore.Put(c, ckey, conference)
		return err

	}, &datastore.TransactionOptions{XG: true})
}
<|endoftext|>


<commit_before>// Copyright © 2015 Steve Francia <spf@spf13.com>.
//
// 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 cmd

import (
	"fmt"
	"os"
	"unicode"

	"github.com/spf13/cobra"
)

var (
	packageName string
	parentName  string

	addCmd = &cobra.Command{
		Use:     "add [command name]",
		Aliases: []string{"command"},
		Short:   "Add a command to a Cobra Application",
		Long: `Add (cobra add) will create a new command, with a license and
the appropriate structure for a Cobra-based CLI application,
and register it to its parent (default rootCmd).

If you want your command to be public, pass in the command name
with an initial uppercase letter.

Example: cobra add server -> resulting in a new cmd/server.go`,

		Run: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				er("add needs a name for the command")
			}

			commandName := validateCmdName(args[0])

			if packageName == "" {
				// derive packageName
			}

			wd, err := os.Getwd()
			if err != nil {
				er(err)
			}

			command := &Command{
				CmdName:   commandName,
				CmdParent: parentName,
				Project: &Project{
					AbsolutePath: fmt.Sprintf("%s/cmd", wd),
					//AppName:      path.Base(packageName),
					//PkgName:      packageName,
					Legal:     getLicense(),
					Copyright: copyrightLine(),
				},
			}

			err = command.Create()
			if err != nil {
				er(err)
			}

			fmt.Printf("%s created at %s", command.CmdName, command.Project.AbsolutePath)
		},
	}
)

func init() {
	addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
	addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command")
}

// validateCmdName returns source without any dashes and underscore.
// If there will be dash or underscore, next letter will be uppered.
// It supports only ASCII (1-byte character) strings.
// https://github.com/spf13/cobra/issues/269
func validateCmdName(source string) string {
	i := 0
	l := len(source)
	// The output is initialized on demand, then first dash or underscore
	// occurs.
	var output string

	for i < l {
		if source[i] == '-' || source[i] == '_' {
			if output == "" {
				output = source[:i]
			}

			// If it's last rune and it's dash or underscore,
			// don't add it output and break the loop.
			if i == l-1 {
				break
			}

			// If next character is dash or underscore,
			// just skip the current character.
			if source[i+1] == '-' || source[i+1] == '_' {
				i++
				continue
			}

			// If the current character is dash or underscore,
			// upper next letter and add to output.
			output += string(unicode.ToUpper(rune(source[i+1])))
			// We know, what source[i] is dash or underscore and source[i+1] is
			// uppered character, so make i = i+2.
			i += 2
			continue
		}

		// If the current character isn't dash or underscore,
		// just add it.
		if output != "" {
			output += string(source[i])
		}
		i++
	}

	if output == "" {
		return source // source is initially valid name.
	}
	return output
}
<commit_msg>reorder some operations<commit_after>// Copyright © 2015 Steve Francia <spf@spf13.com>.
//
// 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 cmd

import (
	"fmt"
	"os"
	"unicode"

	"github.com/spf13/cobra"
)

var (
	packageName string
	parentName  string

	addCmd = &cobra.Command{
		Use:     "add [command name]",
		Aliases: []string{"command"},
		Short:   "Add a command to a Cobra Application",
		Long: `Add (cobra add) will create a new command, with a license and
the appropriate structure for a Cobra-based CLI application,
and register it to its parent (default rootCmd).

If you want your command to be public, pass in the command name
with an initial uppercase letter.

Example: cobra add server -> resulting in a new cmd/server.go`,

		Run: func(cmd *cobra.Command, args []string) {
			if len(args) < 1 {
				er("add needs a name for the command")
			}

			wd, err := os.Getwd()
			if err != nil {
				er(err)
			}

			commandName := validateCmdName(args[0])
			command := &Command{
				CmdName:   commandName,
				CmdParent: parentName,
				Project: &Project{
					AbsolutePath: fmt.Sprintf("%s/cmd", wd),
					//AppName:      path.Base(packageName),
					//PkgName:      packageName,
					Legal:     getLicense(),
					Copyright: copyrightLine(),
				},
			}

			err = command.Create()
			if err != nil {
				er(err)
			}

			fmt.Printf("%s created at %s", command.CmdName, command.Project.AbsolutePath)
		},
	}
)

func init() {
	addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
	addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command")
}

// validateCmdName returns source without any dashes and underscore.
// If there will be dash or underscore, next letter will be uppered.
// It supports only ASCII (1-byte character) strings.
// https://github.com/spf13/cobra/issues/269
func validateCmdName(source string) string {
	i := 0
	l := len(source)
	// The output is initialized on demand, then first dash or underscore
	// occurs.
	var output string

	for i < l {
		if source[i] == '-' || source[i] == '_' {
			if output == "" {
				output = source[:i]
			}

			// If it's last rune and it's dash or underscore,
			// don't add it output and break the loop.
			if i == l-1 {
				break
			}

			// If next character is dash or underscore,
			// just skip the current character.
			if source[i+1] == '-' || source[i+1] == '_' {
				i++
				continue
			}

			// If the current character is dash or underscore,
			// upper next letter and add to output.
			output += string(unicode.ToUpper(rune(source[i+1])))
			// We know, what source[i] is dash or underscore and source[i+1] is
			// uppered character, so make i = i+2.
			i += 2
			continue
		}

		// If the current character isn't dash or underscore,
		// just add it.
		if output != "" {
			output += string(source[i])
		}
		i++
	}

	if output == "" {
		return source // source is initially valid name.
	}
	return output
}
<|endoftext|>