<commit_before>package db

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path"

	"github.com/briantigerchow/go-multihash/multihash"
	api "github.com/danmane/abalone/go/api"
	"github.com/jinzhu/gorm"
)

type playersDB struct {
	db              *gorm.DB
	filestoragePath string
}

func (s *playersDB) Create(userID int64, p api.Player) (*api.Player, error) {
	p.AuthorId = userID
	if err := s.db.Create(&p).Error; err != nil {
		return nil, err
	}
	return &p, nil
}

func (s *playersDB) Upload(userID int64, p api.Player, executable io.Reader) (*api.Player, error) {

	var buf bytes.Buffer
	io.Copy(&buf, executable)
	hash, err := multihash.Sum(buf.Bytes(), multihash.SHA2_256)
	if err != nil {
		return nil, err
	}
	hashstr := hash.HexString()
	if err := ioutil.WriteFile(path.Join(s.filestoragePath, hashstr), buf.Bytes(), os.ModePerm); err != nil {
		return nil, err
	}

	p.AuthorId = userID
	p.Path = hash.HexString()
	if err := s.db.Create(&p).Error; err != nil {
		return nil, err
	}
	return &p, nil
}

func (s *playersDB) List() ([]api.Player, error) {
	var players []api.Player
	if err := s.db.Find(&players).Error; err != nil {
		return nil, err
	}
	return players, nil
}

func (s *playersDB) Delete(id int64) error {
	return s.db.Delete(api.Player{ID: id}).Error
}

var _ api.PlayersService = &playersDB{}
<commit_msg>style<commit_after>package db

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"path"

	"github.com/briantigerchow/go-multihash/multihash"
	api "github.com/danmane/abalone/go/api"
	"github.com/jinzhu/gorm"
)

type playersDB struct {
	DB              *gorm.DB
	filestoragePath string // TODO extract blobstore
}

func (s *playersDB) Create(userID int64, p api.Player) (*api.Player, error) {
	p.AuthorId = userID
	if err := s.DB.Create(&p).Error; err != nil {
		return nil, err
	}
	return &p, nil
}

func (s *playersDB) Upload(userID int64, p api.Player, executable io.Reader) (*api.Player, error) {

	var buf bytes.Buffer
	io.Copy(&buf, executable)
	hash, err := multihash.Sum(buf.Bytes(), multihash.SHA2_256)
	if err != nil {
		return nil, err
	}
	hashstr := hash.HexString()
	if err := ioutil.WriteFile(path.Join(s.filestoragePath, hashstr), buf.Bytes(), os.ModePerm); err != nil {
		return nil, err
	}

	p.AuthorId = userID
	p.Path = hash.HexString()
	if err := s.DB.Create(&p).Error; err != nil {
		return nil, err
	}
	return &p, nil
}

func (s *playersDB) List() ([]api.Player, error) {
	var players []api.Player
	if err := s.DB.Find(&players).Error; err != nil {
		return nil, err
	}
	return players, nil
}

func (s *playersDB) Delete(id int64) error {
	return s.DB.Delete(api.Player{ID: id}).Error
}

var _ api.PlayersService = &playersDB{}
<|endoftext|>


<commit_before>package syscalls

import (
	"fmt"
	"github.com/lunixbochs/struc"
	"os"
	"syscall"

	"../models"
)

func errno(err error) uint64 {
	if err != nil {
		return ^uint64(err.(syscall.Errno))
	}
	return 0
}

type U models.Usercorn

type Syscall struct {
	Func func(u U, a []uint64) uint64
	Args []int
	Ret  int
}

func exit(u U, a []uint64) uint64 {
	code := int(a[0])
	syscall.Exit(code)
	return 0
}

func read(u U, a []uint64) uint64 {
	fd, buf, size := int(a[0]), a[1], a[2]
	tmp := make([]byte, size)
	n, _ := syscall.Read(fd, tmp)
	u.MemWrite(buf, tmp[:n])
	return uint64(n)
}

func write(u U, a []uint64) uint64 {
	fd, buf, size := int(a[0]), a[1], a[2]
	mem, _ := u.MemRead(buf, size)
	n, _ := syscall.Write(fd, mem)
	return uint64(n)
}

func open(u U, a []uint64) uint64 {
	path, _ := u.MemReadStr(a[0])
	mode, flags := int(a[1]), uint32(a[2])
	fd, _ := syscall.Open(path, mode, flags)
	return uint64(fd)
}

func _close(u U, a []uint64) uint64 {
	fd := int(a[0])
	syscall.Close(fd)
	return 0
}

func lseek(u U, a []uint64) uint64 {
	fd, offset, whence := int(a[0]), int64(a[1]), int(a[2])
	off, _ := syscall.Seek(fd, offset, whence)
	return uint64(off)
}

func mmap(u U, a []uint64) uint64 {
	addr_hint, size, prot, flags, fd, off := a[0], a[1], a[2], a[3], int(int32(a[4])), int64(a[5])
	prot, flags = flags, prot // ignore go error
	addr, _ := u.Mmap(addr_hint, size)
	if fd > 0 {
		fd2, _ := syscall.Dup(fd)
		f := os.NewFile(uintptr(fd2), "")
		f.Seek(off, 0)
		tmp := make([]byte, size)
		n, _ := f.Read(tmp)
		u.MemWrite(addr, tmp[:n])
	}
	return uint64(addr)
}

func munmap(u U, a []uint64) uint64 {
	return 0
}

func mprotect(u U, a []uint64) uint64 {
	return 0
}

func brk(u U, a []uint64) uint64 {
	// TODO: return is Linux specific
	addr := a[0]
	ret, _ := u.Brk(addr)
	return ret
}

func fstat(u U, a []uint64) uint64 {
	fd, buf := int(a[0]), a[1]
	var stat syscall.Stat_t
	err := syscall.Fstat(fd, &stat)
	if err != nil {
		return 1
	}
	err = struc.Pack(u.MemWriter(buf), &stat)
	if err != nil {
		panic(err)
	}
	return 0
}

func getcwd(u U, a []uint64) uint64 {
	buf, size := a[0], a[1]
	wd, _ := os.Getwd()
	if uint64(len(wd)) > size {
		wd = wd[:size]
	}
	u.MemWrite(buf, []byte(wd))
	return 0
}

func access(u U, a []uint64) uint64 {
	// TODO: portability
	path, _ := u.MemReadStr(a[0])
	amode := uint32(a[1])
	err := syscall.Access(path, amode)
	return errno(err)
}

func readv(u U, a []uint64) uint64 {
	fd, iov, count := int(a[0]), a[1], a[2]
	for vec := range iovecIter(u.MemReader(iov), count, int(u.Bits()), u.ByteOrder()) {
		data, _ := u.MemRead(vec.Base, vec.Len)
		syscall.Write(fd, data)
	}
	return 0
}

func writev(u U, a []uint64) uint64 {
	fd, iov, count := int(a[0]), a[1], a[2]
	for vec := range iovecIter(u.MemReader(iov), count, int(u.Bits()), u.ByteOrder()) {
		tmp := make([]byte, vec.Len)
		n, _ := syscall.Read(fd, tmp)
		if n <= 0 {
			break
		}
		u.MemWrite(vec.Base, tmp[:n])
	}
	return 0
}

type A []int

var syscalls = map[string]Syscall{
	"exit": {exit, A{INT}, INT},
	// "fork": {fork, A{}, INT},
	"read":     {read, A{FD, OBUF, LEN}, INT},
	"write":    {write, A{FD, BUF, LEN}, INT},
	"open":     {open, A{STR, INT, INT}, FD},
	"close":    {_close, A{FD}, INT},
	"lseek":    {lseek, A{FD, OFF, INT}, INT},
	"mmap":     {mmap, A{PTR, LEN, INT, INT, FD, OFF}, PTR},
	"munmap":   {munmap, A{PTR, LEN}, INT},
	"mprotect": {mprotect, A{PTR, LEN, INT}, INT},
	"brk":      {brk, A{PTR}, PTR},
	"fstat":    {fstat, A{FD, PTR}, INT},
	"getcwd":   {getcwd, A{PTR, LEN}, INT},
	"access":   {access, A{STR, INT}, INT},
	"readv":    {readv, A{FD, PTR, INT}, INT},
	"writev":   {writev, A{FD, PTR, INT}, INT},
}

func Call(u models.Usercorn, num int, name string, getArgs func(n int) ([]uint64, error), strace bool) (uint64, error) {
	s, ok := syscalls[name]
	if !ok {
		panic(fmt.Errorf("Unknown syscall: %s", name))
	}
	args, err := getArgs(len(s.Args))
	if err != nil {
		return 0, err
	}
	if strace {
		Trace(u, name, args)
	}
	ret := s.Func(u, args)
	if strace {
		TraceRet(u, name, args, ret)
	}
	return ret, nil
}
<commit_msg>fix inverted readv/writev<commit_after>package syscalls

import (
	"fmt"
	"github.com/lunixbochs/struc"
	"os"
	"syscall"

	"../models"
)

func errno(err error) uint64 {
	if err != nil {
		return ^uint64(err.(syscall.Errno))
	}
	return 0
}

type U models.Usercorn

type Syscall struct {
	Func func(u U, a []uint64) uint64
	Args []int
	Ret  int
}

func exit(u U, a []uint64) uint64 {
	code := int(a[0])
	syscall.Exit(code)
	return 0
}

func read(u U, a []uint64) uint64 {
	fd, buf, size := int(a[0]), a[1], a[2]
	tmp := make([]byte, size)
	n, _ := syscall.Read(fd, tmp)
	u.MemWrite(buf, tmp[:n])
	return uint64(n)
}

func write(u U, a []uint64) uint64 {
	fd, buf, size := int(a[0]), a[1], a[2]
	mem, _ := u.MemRead(buf, size)
	n, _ := syscall.Write(fd, mem)
	return uint64(n)
}

func open(u U, a []uint64) uint64 {
	path, _ := u.MemReadStr(a[0])
	mode, flags := int(a[1]), uint32(a[2])
	fd, _ := syscall.Open(path, mode, flags)
	return uint64(fd)
}

func _close(u U, a []uint64) uint64 {
	fd := int(a[0])
	syscall.Close(fd)
	return 0
}

func lseek(u U, a []uint64) uint64 {
	fd, offset, whence := int(a[0]), int64(a[1]), int(a[2])
	off, _ := syscall.Seek(fd, offset, whence)
	return uint64(off)
}

func mmap(u U, a []uint64) uint64 {
	addr_hint, size, prot, flags, fd, off := a[0], a[1], a[2], a[3], int(int32(a[4])), int64(a[5])
	prot, flags = flags, prot // ignore go error
	addr, _ := u.Mmap(addr_hint, size)
	if fd > 0 {
		fd2, _ := syscall.Dup(fd)
		f := os.NewFile(uintptr(fd2), "")
		f.Seek(off, 0)
		tmp := make([]byte, size)
		n, _ := f.Read(tmp)
		u.MemWrite(addr, tmp[:n])
	}
	return uint64(addr)
}

func munmap(u U, a []uint64) uint64 {
	return 0
}

func mprotect(u U, a []uint64) uint64 {
	return 0
}

func brk(u U, a []uint64) uint64 {
	// TODO: return is Linux specific
	addr := a[0]
	ret, _ := u.Brk(addr)
	return ret
}

func fstat(u U, a []uint64) uint64 {
	fd, buf := int(a[0]), a[1]
	var stat syscall.Stat_t
	err := syscall.Fstat(fd, &stat)
	if err != nil {
		return 1
	}
	err = struc.Pack(u.MemWriter(buf), &stat)
	if err != nil {
		panic(err)
	}
	return 0
}

func getcwd(u U, a []uint64) uint64 {
	buf, size := a[0], a[1]
	wd, _ := os.Getwd()
	if uint64(len(wd)) > size {
		wd = wd[:size]
	}
	u.MemWrite(buf, []byte(wd))
	return 0
}

func access(u U, a []uint64) uint64 {
	// TODO: portability
	path, _ := u.MemReadStr(a[0])
	amode := uint32(a[1])
	err := syscall.Access(path, amode)
	return errno(err)
}

func readv(u U, a []uint64) uint64 {
	fd, iov, count := int(a[0]), a[1], a[2]
	for vec := range iovecIter(u.MemReader(iov), count, int(u.Bits()), u.ByteOrder()) {
		tmp := make([]byte, vec.Len)
		n, _ := syscall.Read(fd, tmp)
		if n <= 0 {
			break
		}
		u.MemWrite(vec.Base, tmp[:n])
	}
	return 0
}

func writev(u U, a []uint64) uint64 {
	fd, iov, count := int(a[0]), a[1], a[2]
	for vec := range iovecIter(u.MemReader(iov), count, int(u.Bits()), u.ByteOrder()) {
		data, _ := u.MemRead(vec.Base, vec.Len)
		syscall.Write(fd, data)
	}
	return 0
}

type A []int

var syscalls = map[string]Syscall{
	"exit": {exit, A{INT}, INT},
	// "fork": {fork, A{}, INT},
	"read":     {read, A{FD, OBUF, LEN}, INT},
	"write":    {write, A{FD, BUF, LEN}, INT},
	"open":     {open, A{STR, INT, INT}, FD},
	"close":    {_close, A{FD}, INT},
	"lseek":    {lseek, A{FD, OFF, INT}, INT},
	"mmap":     {mmap, A{PTR, LEN, INT, INT, FD, OFF}, PTR},
	"munmap":   {munmap, A{PTR, LEN}, INT},
	"mprotect": {mprotect, A{PTR, LEN, INT}, INT},
	"brk":      {brk, A{PTR}, PTR},
	"fstat":    {fstat, A{FD, PTR}, INT},
	"getcwd":   {getcwd, A{PTR, LEN}, INT},
	"access":   {access, A{STR, INT}, INT},
	"readv":    {readv, A{FD, PTR, INT}, INT},
	"writev":   {writev, A{FD, PTR, INT}, INT},
}

func Call(u models.Usercorn, num int, name string, getArgs func(n int) ([]uint64, error), strace bool) (uint64, error) {
	s, ok := syscalls[name]
	if !ok {
		panic(fmt.Errorf("Unknown syscall: %s", name))
	}
	args, err := getArgs(len(s.Args))
	if err != nil {
		return 0, err
	}
	if strace {
		Trace(u, name, args)
	}
	ret := s.Func(u, args)
	if strace {
		TraceRet(u, name, args, ret)
	}
	return ret, nil
}
<|endoftext|>


<commit_before>package triangle

const testVersion = 3

func KindFromSides(a, b, c float64) Kind

// Notice KindFromSides() returns this type. Pick a suitable data type.
type Kind

// Pick values for the following identifiers used by the test program.
NaT // not a triangle
Equ // equilateral
Iso // isosceles
Sca // scalene

// Organize your code for readability.
<commit_msg>triangle.go ok<commit_after>package triangle

import "math"

const testVersion = 3

func KindFromSides(a, b, c float64) Kind {
	result := NaT
	if a > 0 && b > 0 && c > 0 && !math.IsInf(a, 1) && !math.IsInf(b, 1) && !math.IsInf(c, 1) && a+b >= c && a+c >= b && b+c >= a {
		if a == b && a == c && b == c {
			result = Equ
		} else if a == b || a == c || b == c {
			result = Iso
		} else {
			result = Sca
		}

	}
	return result
}

type Kind int

const (
	NaT Kind = 0
	Equ      = 1
	Iso      = 2
	Sca      = 3
)
<|endoftext|>


<commit_before>package scan

import (
	"bufio"
	"errors"
	"io"
	"log"
	"regexp"
	"strings"
)

// endOfSource is returned when io.EOF is reached in one of
// the sources and there are still more sources to process.
var endOfSource = errors.New("end of source")

type Source interface {
	io.Reader

	// Name returns the name of the source.
	Name() string
}

func MultiSource(sources ...Source) Source {
	return &multiSource{sources}
}

type multiSource struct {
	sources []Source
}

func (ms *multiSource) Read(p []byte) (n int, err error) {
	for len(ms.sources) > 0 {
		n, err = ms.sources[0].Read(p)
		if err == io.EOF {
			ms.sources = ms.sources[1:]
			if len(ms.sources) > 0 {
				err = endOfSource
				return
			}
		}
		if n > 0 || err != nil {
			return
		}
	}
	return 0, io.EOF
}

func (ms *multiSource) Name() string {
	if len(ms.sources) == 0 {
		return ""
	}
	return ms.sources[0].Name()
}

// A Scanner is used for splitting input into rows and
// splitting rows into fields.
type Scanner struct {
	lr       lineReader
	rowsRx   *regexp.Regexp
	fieldsRx *regexp.Regexp
	err      error // sticky err

	recNumber     int
	fileRecNumber int
	rec           string
	fields        []string
}

// SetReader sets an io.Reader for scanner to read from.
func (sc *Scanner) SetSource(src Source) {
	if sc.rowsRx != nil {
		sc.lr = newRxLineReader(src, sc.rowsRx)
	} else {
		sc.lr = newSimpleLineReader(src)
	}
	sc.recNumber = 0
}

// SetRowSep sets regexp rx that will be used to separate
// input into rows.
func (sc *Scanner) SetRowSep(rx string) {
	if sc.err != nil {
		return
	}
	sc.rowsRx, sc.err = regexp.Compile(rx)
	if sc.err == nil && sc.lr != nil {
		sc.lr = newRxLineReader(sc.lr, sc.rowsRx)
	}
}

// SetFieldSep sets regexp rx that will be used to separate
// row into fields.
func (sc *Scanner) SetFieldSep(rx string) {
	if sc.err != nil {
		return
	}
	sc.fieldsRx, sc.err = regexp.Compile(rx)
}

// Scan scans another record and parses it into fields. It there
// is an error or EOF is reached, Scan returns false. Otherwise
// it returns true.
func (sc *Scanner) Scan() bool {
	if sc.err != nil {
		return false
	}
	if sc.lr == nil {
		sc.err = errors.New("scan: nil reader")
		return false
	}

readRecord:
	line, err := sc.lr.ReadLine()
	if err == io.EOF {
		return false
	} else if err == endOfSource {
		sc.fileRecNumber = 0
		goto readRecord
	} else if err != nil {
		sc.err = err
		return false
	}
	sc.splitRecord(line)
	sc.recNumber++
	sc.fileRecNumber++
	return true
}

func (sc *Scanner) splitRecord(rec []byte) {
	sc.rec = string(rec)
	if sc.fieldsRx != nil {
		sc.fields = sc.fieldsRx.Split(sc.rec, -1)
		if len(sc.fields) > 0 && sc.fields[0] == "" {
			sc.fields = sc.fields[1:]
		}
		if len(sc.fields) > 0 && sc.fields[len(sc.fields)-1] == "" {
			sc.fields = sc.fields[:len(sc.fields)-1]
		}
	} else {
		sc.fields = strings.Fields(sc.rec)
	}
}

func (sc *Scanner) Err() error {
	return sc.err
}

// Field returns ith field from the current row.
func (sc *Scanner) Field(i int) string {
	switch {
	case i < 0:
		log.Fatal("attempt to access field -1")
	case i == 0:
		return sc.rec
	case i <= len(sc.fields):
		return sc.fields[i-1]
	}
	return ""
}

// RecordNumber returns the current record number.
func (sc *Scanner) RecordNumber() int {
	return sc.recNumber
}

// FieldCount returns number of fields of the current row.
func (sc *Scanner) FieldCount() int {
	return len(sc.fields)
}

// Filename returns the name of the currently processed file.
func (sc *Scanner) Filename() string {
	return sc.lr.Name()
}

// FileRecordNumber returns the current record number in the currently
// processed file.
func (sc *Scanner) FileRecordNumber() int {
	return sc.fileRecNumber
}

type lineReader interface {
	Source // to be able to read buffered data
	ReadLine() ([]byte, error)
}

type simpleLineReader struct {
	src  Source
	name string // name of the current source
	br   *bufio.Reader
}

func newSimpleLineReader(src Source) *simpleLineReader {
	return &simpleLineReader{
		src:  src,
		name: src.Name(),
		br:   bufio.NewReader(src),
	}
}

func (sr *simpleLineReader) Read(p []byte) (n int, err error) {
	n, err = sr.br.Read(p)
	if err == endOfSource {
		sr.name = sr.src.Name()
	}
	return
}

func (sr *simpleLineReader) Name() string { return sr.name }

func (sr *simpleLineReader) ReadLine() ([]byte, error) {
	line, err := sr.br.ReadBytes('\n')
	if len(line) > 0 {
		line = line[:len(line)-1] // remove '\n'
	}
	return line, err
}

const bufSize = 4096

var _bufSize = bufSize // for testing purposes

type rxLineReader struct {
	buf      [bufSize]byte
	ptr      []byte
	src      Source
	name     string // name of the current source
	rx       *regexp.Regexp
	eos      bool
	finished bool
}

func newRxLineReader(src Source, sepRx *regexp.Regexp) *rxLineReader {
	return &rxLineReader{
		src:  src,
		name: src.Name(),
		rx:   sepRx,
	}
}

func (rr *rxLineReader) Read(p []byte) (n int, err error) {
	if len(rr.ptr) > 0 {
		n := copy(p, rr.ptr)
		rr.ptr = rr.ptr[n:]
		return n, nil
	}
	return rr.src.Read(p)
}

func (rr *rxLineReader) Name() string {
	if len(rr.ptr) > 0 {
		return rr.name
	}
	return rr.src.Name()
}

func (rr *rxLineReader) ReadLine() (line []byte, err error) {
	var loc []int
	for {
		if len(rr.ptr) == 0 {
		End:
			if rr.finished {
				if len(line) > 0 {
					if loc != nil {
						line = line[:loc[0]]
					}
					return line, nil
				}
				return nil, io.EOF
			}
			if err := rr.loadBuf(); err != nil {
				return nil, err
			}
			if rr.finished {
				goto End
			}
		}
		line = append(line, rr.ptr...)
		loc = rr.rx.FindIndex(line)

		if loc == nil || loc[1] == len(line) {
			rr.ptr = nil

			if rr.eos {
				rr.eos = false
				if loc != nil {
					line = line[:loc[0]]
				}
				return line, nil
			}
			continue
		}

		rr.ptr = line[loc[1]:]
		return line[:loc[0]], nil
	}
}

func (rr *rxLineReader) loadBuf() error { return rr.loadBufN(_bufSize) }

func (rr *rxLineReader) loadBufN(n int) error {
	m, err := rr.src.Read(rr.buf[:n])
	rr.ptr = rr.buf[:m]
	if err == io.EOF {
		rr.finished = true
	} else if err == endOfSource {
		rr.name = rr.src.Name()
		rr.eos = true
	} else {
		return err
	}
	return nil
}
<commit_msg>scan: Improve doc<commit_after>package scan

import (
	"bufio"
	"errors"
	"io"
	"log"
	"regexp"
	"strings"
)

// endOfSource is returned when io.EOF is reached in one of
// the sources and there are still more sources to process.
var endOfSource = errors.New("end of source")

// Source is the interface thats wraps io.Reader and provides
// the Name method.
type Source interface {
	io.Reader

	// Name returns the name of the source.
	Name() string
}

// MultiSource returns a Source that's the logical concatenation
// of the provided input sources.
func MultiSource(sources ...Source) Source {
	return &multiSource{sources}
}

type multiSource struct {
	sources []Source
}

func (ms *multiSource) Read(p []byte) (n int, err error) {
	for len(ms.sources) > 0 {
		n, err = ms.sources[0].Read(p)
		if err == io.EOF {
			ms.sources = ms.sources[1:]
			if len(ms.sources) > 0 {
				err = endOfSource
				return
			}
		}
		if n > 0 || err != nil {
			return
		}
	}
	return 0, io.EOF
}

func (ms *multiSource) Name() string {
	if len(ms.sources) == 0 {
		return ""
	}
	return ms.sources[0].Name()
}

// A Scanner is used for splitting input into rows and
// splitting rows into fields.
type Scanner struct {
	lr       lineReader
	rowsRx   *regexp.Regexp
	fieldsRx *regexp.Regexp
	err      error // sticky err

	recNumber     int
	fileRecNumber int
	rec           string
	fields        []string
}

// SetReader sets an io.Reader for scanner to read from.
func (sc *Scanner) SetSource(src Source) {
	if sc.rowsRx != nil {
		sc.lr = newRxLineReader(src, sc.rowsRx)
	} else {
		sc.lr = newSimpleLineReader(src)
	}
	sc.recNumber = 0
}

// SetRowSep sets regexp rx that will be used to separate
// input into rows.
func (sc *Scanner) SetRowSep(rx string) {
	if sc.err != nil {
		return
	}
	sc.rowsRx, sc.err = regexp.Compile(rx)
	if sc.err == nil && sc.lr != nil {
		sc.lr = newRxLineReader(sc.lr, sc.rowsRx)
	}
}

// SetFieldSep sets regexp rx that will be used to separate
// row into fields.
func (sc *Scanner) SetFieldSep(rx string) {
	if sc.err != nil {
		return
	}
	sc.fieldsRx, sc.err = regexp.Compile(rx)
}

// Scan scans another record and parses it into fields. It there
// is an error or EOF is reached, Scan returns false. Otherwise
// it returns true.
func (sc *Scanner) Scan() bool {
	if sc.err != nil {
		return false
	}
	if sc.lr == nil {
		sc.err = errors.New("scan: nil reader")
		return false
	}

readRecord:
	line, err := sc.lr.ReadLine()
	if err == io.EOF {
		return false
	} else if err == endOfSource {
		sc.fileRecNumber = 0
		goto readRecord
	} else if err != nil {
		sc.err = err
		return false
	}
	sc.splitRecord(line)
	sc.recNumber++
	sc.fileRecNumber++
	return true
}

func (sc *Scanner) splitRecord(rec []byte) {
	sc.rec = string(rec)
	if sc.fieldsRx != nil {
		sc.fields = sc.fieldsRx.Split(sc.rec, -1)
		if len(sc.fields) > 0 && sc.fields[0] == "" {
			sc.fields = sc.fields[1:]
		}
		if len(sc.fields) > 0 && sc.fields[len(sc.fields)-1] == "" {
			sc.fields = sc.fields[:len(sc.fields)-1]
		}
	} else {
		sc.fields = strings.Fields(sc.rec)
	}
}

func (sc *Scanner) Err() error {
	return sc.err
}

// Field returns ith field from the current row.
func (sc *Scanner) Field(i int) string {
	switch {
	case i < 0:
		log.Fatal("attempt to access field -1")
	case i == 0:
		return sc.rec
	case i <= len(sc.fields):
		return sc.fields[i-1]
	}
	return ""
}

// RecordNumber returns the current record number.
func (sc *Scanner) RecordNumber() int {
	return sc.recNumber
}

// FieldCount returns number of fields of the current row.
func (sc *Scanner) FieldCount() int {
	return len(sc.fields)
}

// Filename returns the name of the currently processed source.
func (sc *Scanner) Filename() string {
	return sc.lr.Name()
}

// FileRecordNumber returns the current record number in the currently
// processed file.
func (sc *Scanner) FileRecordNumber() int {
	return sc.fileRecNumber
}

type lineReader interface {
	Source // to be able to read buffered data
	ReadLine() ([]byte, error)
}

type simpleLineReader struct {
	src  Source
	name string // name of the current source
	br   *bufio.Reader
}

func newSimpleLineReader(src Source) *simpleLineReader {
	return &simpleLineReader{
		src:  src,
		name: src.Name(),
		br:   bufio.NewReader(src),
	}
}

func (sr *simpleLineReader) Read(p []byte) (n int, err error) {
	n, err = sr.br.Read(p)
	if err == endOfSource {
		sr.name = sr.src.Name()
	}
	return
}

func (sr *simpleLineReader) Name() string { return sr.name }

func (sr *simpleLineReader) ReadLine() ([]byte, error) {
	line, err := sr.br.ReadBytes('\n')
	if len(line) > 0 {
		line = line[:len(line)-1] // remove '\n'
	}
	return line, err
}

const bufSize = 4096

var _bufSize = bufSize // for testing purposes

type rxLineReader struct {
	buf      [bufSize]byte
	ptr      []byte
	src      Source
	name     string // name of the current source
	rx       *regexp.Regexp
	eos      bool
	finished bool
}

func newRxLineReader(src Source, sepRx *regexp.Regexp) *rxLineReader {
	return &rxLineReader{
		src:  src,
		name: src.Name(),
		rx:   sepRx,
	}
}

func (rr *rxLineReader) Read(p []byte) (n int, err error) {
	if len(rr.ptr) > 0 {
		n := copy(p, rr.ptr)
		rr.ptr = rr.ptr[n:]
		return n, nil
	}
	return rr.src.Read(p)
}

func (rr *rxLineReader) Name() string {
	if len(rr.ptr) > 0 {
		return rr.name
	}
	return rr.src.Name()
}

func (rr *rxLineReader) ReadLine() (line []byte, err error) {
	var loc []int
	for {
		if len(rr.ptr) == 0 {
		End:
			if rr.finished {
				if len(line) > 0 {
					if loc != nil {
						line = line[:loc[0]]
					}
					return line, nil
				}
				return nil, io.EOF
			}
			if err := rr.loadBuf(); err != nil {
				return nil, err
			}
			if rr.finished {
				goto End
			}
		}
		line = append(line, rr.ptr...)
		loc = rr.rx.FindIndex(line)

		if loc == nil || loc[1] == len(line) {
			rr.ptr = nil

			if rr.eos {
				rr.eos = false
				if loc != nil {
					line = line[:loc[0]]
				}
				return line, nil
			}
			continue
		}

		rr.ptr = line[loc[1]:]
		return line[:loc[0]], nil
	}
}

func (rr *rxLineReader) loadBuf() error { return rr.loadBufN(_bufSize) }

func (rr *rxLineReader) loadBufN(n int) error {
	m, err := rr.src.Read(rr.buf[:n])
	rr.ptr = rr.buf[:m]
	if err == io.EOF {
		rr.finished = true
	} else if err == endOfSource {
		rr.name = rr.src.Name()
		rr.eos = true
	} else {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package nsqd

import (
	//"github.com/absolute8511/nsq/internal/levellogger"
	"os"
	"strconv"
	"testing"
	"time"
)

// ensure that we can push a message through a topic and get it out of a channel
func TestPutMessage(t *testing.T) {
	opts := NewOptions()
	opts.Logger = newTestLogger(t)
	//opts.Logger = &levellogger.GLogger{}
	opts.LogLevel = 3
	opts.SyncEvery = 1
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_put_message" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel1 := topic.GetChannel("ch")

	var id MessageID
	msg := NewMessage(id, []byte("test"))
	topic.PutMessage(msg)
	topic.flush(true)

	outputMsg := <-channel1.clientMsgChan
	equal(t, msg.ID, outputMsg.ID)
	equal(t, msg.Body, outputMsg.Body)
}

// ensure that both channels get the same message
func TestPutMessage2Chan(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_put_message_2chan" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel1 := topic.GetChannel("ch1")
	channel2 := topic.GetChannel("ch2")

	var id MessageID
	msg := NewMessage(id, []byte("test"))
	topic.PutMessage(msg)
	topic.flush(true)

	outputMsg1 := <-channel1.clientMsgChan
	equal(t, msg.ID, outputMsg1.ID)
	equal(t, msg.Body, outputMsg1.Body)

	outputMsg2 := <-channel2.clientMsgChan
	equal(t, msg.ID, outputMsg2.ID)
	equal(t, msg.Body, outputMsg2.Body)
}

func TestChannelBackendMaxMsgSize(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_backend_maxmsgsize" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)

	equal(t, topic.backend.maxMsgSize, int32(opts.MaxMsgSize+minValidMsgLength))
}

func TestInFlightWorker(t *testing.T) {
	count := 250

	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	opts.MsgTimeout = 100 * time.Millisecond
	opts.QueueScanRefreshInterval = 100 * time.Millisecond
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_in_flight_worker" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	for i := 0; i < count; i++ {
		msg := NewMessage(topic.nextMsgID(), []byte("test"))
		channel.StartInFlightTimeout(msg, 0, "", opts.MsgTimeout)
	}

	channel.Lock()
	inFlightMsgs := len(channel.inFlightMessages)
	channel.Unlock()
	equal(t, inFlightMsgs, count)

	channel.inFlightMutex.Lock()
	inFlightPQMsgs := len(channel.inFlightPQ)
	channel.inFlightMutex.Unlock()
	equal(t, inFlightPQMsgs, count)

	// the in flight worker has a resolution of 100ms so we need to wait
	// at least that much longer than our msgTimeout (in worst case)
	time.Sleep(4*opts.MsgTimeout + opts.QueueScanInterval)

	channel.Lock()
	inFlightMsgs = len(channel.inFlightMessages)
	channel.Unlock()
	equal(t, inFlightMsgs, 0)

	channel.inFlightMutex.Lock()
	inFlightPQMsgs = len(channel.inFlightPQ)
	channel.inFlightMutex.Unlock()
	equal(t, inFlightPQMsgs, 0)
}

func TestChannelEmpty(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	msgs := make([]*Message, 0, 25)
	for i := 0; i < 25; i++ {
		msg := NewMessage(topic.nextMsgID(), []byte("test"))
		channel.StartInFlightTimeout(msg, 0, "", opts.MsgTimeout)
		msgs = append(msgs, msg)
	}

	channel.RequeueMessage(0, "", msgs[len(msgs)-1].ID, 0, true)
	equal(t, len(channel.inFlightMessages), 24)
	equal(t, len(channel.inFlightPQ), 24)

	channel.skipChannelToEnd()

	equal(t, len(channel.inFlightMessages), 0)
	equal(t, len(channel.inFlightPQ), 0)
	equal(t, channel.Depth(), int64(0))
}

func TestChannelHealth(t *testing.T) {
	opts := NewOptions()
	opts.Logger = newTestLogger(t)
	opts.MemQueueSize = 2

	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topic := nsqd.GetTopicIgnPart("test")

	channel := topic.GetChannel("channel")
	// cause channel.messagePump to exit so we can set channel.backend without
	// a data race. side effect is it closes clientMsgChan, and messagePump is
	// never restarted. note this isn't the intended usage of exitChan but gets
	// around the data race without more invasive changes to how channel.backend
	// is set/loaded.
	channel.exitChan <- 1
}

func TestChannelSkip(t *testing.T) {
	// TODO: backward and forward
}

func TestChannelResetReadEnd(t *testing.T) {
}

func TestChannelDepthTimestamp(t *testing.T) {
	// handle read no data, reset, etc
}
<commit_msg>channel testcase<commit_after>package nsqd

import (
	//"github.com/absolute8511/nsq/internal/levellogger"
	"os"
	"strconv"
	"testing"
	"time"
)

// ensure that we can push a message through a topic and get it out of a channel
func TestPutMessage(t *testing.T) {
	opts := NewOptions()
	opts.Logger = newTestLogger(t)
	//opts.Logger = &levellogger.GLogger{}
	opts.LogLevel = 3
	opts.SyncEvery = 1
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_put_message" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel1 := topic.GetChannel("ch")

	var id MessageID
	msg := NewMessage(id, []byte("test"))
	topic.PutMessage(msg)
	topic.flush(true)

	outputMsg := <-channel1.clientMsgChan
	equal(t, msg.ID, outputMsg.ID)
	equal(t, msg.Body, outputMsg.Body)
}

// ensure that both channels get the same message
func TestPutMessage2Chan(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_put_message_2chan" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel1 := topic.GetChannel("ch1")
	channel2 := topic.GetChannel("ch2")

	var id MessageID
	msg := NewMessage(id, []byte("test"))
	topic.PutMessage(msg)
	topic.flush(true)

	outputMsg1 := <-channel1.clientMsgChan
	equal(t, msg.ID, outputMsg1.ID)
	equal(t, msg.Body, outputMsg1.Body)

	outputMsg2 := <-channel2.clientMsgChan
	equal(t, msg.ID, outputMsg2.ID)
	equal(t, msg.Body, outputMsg2.Body)
}

func TestChannelBackendMaxMsgSize(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_backend_maxmsgsize" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)

	equal(t, topic.backend.maxMsgSize, int32(opts.MaxMsgSize+minValidMsgLength))
}

func TestInFlightWorker(t *testing.T) {
	count := 250

	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	opts.MsgTimeout = 100 * time.Millisecond
	opts.QueueScanRefreshInterval = 100 * time.Millisecond
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_in_flight_worker" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	for i := 0; i < count; i++ {
		msg := NewMessage(topic.nextMsgID(), []byte("test"))
		channel.StartInFlightTimeout(msg, 0, "", opts.MsgTimeout)
	}

	channel.Lock()
	inFlightMsgs := len(channel.inFlightMessages)
	channel.Unlock()
	equal(t, inFlightMsgs, count)

	channel.inFlightMutex.Lock()
	inFlightPQMsgs := len(channel.inFlightPQ)
	channel.inFlightMutex.Unlock()
	equal(t, inFlightPQMsgs, count)

	// the in flight worker has a resolution of 100ms so we need to wait
	// at least that much longer than our msgTimeout (in worst case)
	time.Sleep(4*opts.MsgTimeout + opts.QueueScanInterval)

	channel.Lock()
	inFlightMsgs = len(channel.inFlightMessages)
	channel.Unlock()
	equal(t, inFlightMsgs, 0)

	channel.inFlightMutex.Lock()
	inFlightPQMsgs = len(channel.inFlightPQ)
	channel.inFlightMutex.Unlock()
	equal(t, inFlightPQMsgs, 0)
}

func TestChannelEmpty(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	msgs := make([]*Message, 0, 25)
	for i := 0; i < 25; i++ {
		msg := NewMessage(topic.nextMsgID(), []byte("test"))
		channel.StartInFlightTimeout(msg, 0, "", opts.MsgTimeout)
		msgs = append(msgs, msg)
	}

	channel.RequeueMessage(0, "", msgs[len(msgs)-1].ID, 0, true)
	equal(t, len(channel.inFlightMessages), 24)
	equal(t, len(channel.inFlightPQ), 24)

	channel.skipChannelToEnd()

	equal(t, len(channel.inFlightMessages), 0)
	equal(t, len(channel.inFlightPQ), 0)
	equal(t, channel.Depth(), int64(0))
}

func TestChannelHealth(t *testing.T) {
	opts := NewOptions()
	opts.Logger = newTestLogger(t)
	opts.MemQueueSize = 2

	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topic := nsqd.GetTopicIgnPart("test")

	channel := topic.GetChannel("channel")
	// cause channel.messagePump to exit so we can set channel.backend without
	// a data race. side effect is it closes clientMsgChan, and messagePump is
	// never restarted. note this isn't the intended usage of exitChan but gets
	// around the data race without more invasive changes to how channel.backend
	// is set/loaded.
	channel.exitChan <- 1
}

func TestChannelSkip(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_skip" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	msgs := make([]*Message, 0, 10)
	for i := 0; i < 10; i++ {
		var msgId MessageID
		msgBytes := []byte(strconv.Itoa(i))
		msg := NewMessage(msgId, msgBytes)
		msgs = append(msgs, msg)
	}
	topic.PutMessages(msgs)

	var msgId MessageID
	msgBytes := []byte(strconv.Itoa(10))
	msg := NewMessage(msgId, msgBytes)
	_, backendOffsetMid, _, _, _ := topic.PutMessage(msg)
	topic.flush(true)
	equal(t, channel.Depth(), int64(11))

	msgs = make([]*Message, 0, 9)
	//put another 10 messages
	for i := 0; i < 9; i++ {
		var msgId MessageID
		msgBytes := []byte(strconv.Itoa(i + 11))
		msg := NewMessage(msgId, msgBytes)
		msgs = append(msgs, msg)
	}
	topic.PutMessages(msgs)
	topic.flush(true)
	equal(t, channel.Depth(), int64(20))

	//skip forward to message 10
	t.Logf("backendOffsetMid: %d", backendOffsetMid)
	channel.SetConsumeOffset(backendOffsetMid, 10, true)
	for i := 0; i < 10; i++ {
		outputMsg := <-channel.clientMsgChan
		equal(t, string(outputMsg.Body[:]), strconv.Itoa(i+10));
	}
}

func TestChannelResetReadEnd(t *testing.T) {
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_skip" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	msgs := make([]*Message, 0, 10)
	for i := 0; i < 10; i++ {
		var msgId MessageID
		msgBytes := []byte(strconv.Itoa(i))
		msg := NewMessage(msgId, msgBytes)
		msgs = append(msgs, msg)
	}
	topic.PutMessages(msgs)

	var msgId MessageID
	msgBytes := []byte(strconv.Itoa(10))
	msg := NewMessage(msgId, msgBytes)
	_, backendOffsetMid, _, _, _ := topic.PutMessage(msg)
	topic.flush(true)
	equal(t, channel.Depth(), int64(11))

	msgs = make([]*Message, 0, 9)
	//put another 10 messages
	for i := 0; i < 9; i++ {
		var msgId MessageID
		msgBytes := []byte(strconv.Itoa(i + 11))
		msg := NewMessage(msgId, msgBytes)
		msgs = append(msgs, msg)
	}
	topic.PutMessages(msgs)
	topic.flush(true)
	equal(t, channel.Depth(), int64(20))

	//skip forward to message 10
	t.Logf("backendOffsetMid: %d", backendOffsetMid)
	channel.SetConsumeOffset(backendOffsetMid, 10, true)
	for i := 0; i < 10; i++ {
		outputMsg := <-channel.clientMsgChan
		equal(t, string(outputMsg.Body[:]), strconv.Itoa(i+10));
	}
	equal(t, channel.Depth(), int64(10))

	channel.SetConsumeOffset(0, 0, true)
	//equal(t, channel.Depth(), int64(20))
	for i := 0; i < 20; i++ {
		outputMsg := <-channel.clientMsgChan
		t.Logf("Msg: %s", outputMsg.Body)
		equal(t, string(outputMsg.Body[:]), strconv.Itoa(i));
	}
}

func TestChannelDepthTimestamp(t *testing.T) {
	// handle read no data, reset, etc
	opts := NewOptions()
	opts.SyncEvery = 1
	opts.Logger = newTestLogger(t)
	_, _, nsqd := mustStartNSQD(opts)
	defer os.RemoveAll(opts.DataPath)
	defer nsqd.Exit()

	topicName := "test_channel_depthts" + strconv.Itoa(int(time.Now().Unix()))
	topic := nsqd.GetTopicIgnPart(topicName)
	channel := topic.GetChannel("channel")

	msgs := make([]*Message, 0, 9)
	//put another 10 messages
	for i := 0; i < 10; i++ {
		var msgId MessageID
		msgBytes := []byte(strconv.Itoa(i + 11))
		msg := NewMessage(msgId, msgBytes)
		msgs = append(msgs, msg)
	}
	topic.PutMessages(msgs)
	topic.flush(true)

	for i := 0; i < 10; i++ {
		msgOutput := <- channel.clientMsgChan
		equal(t, msgOutput.Timestamp, channel.DepthTimestamp());
	}
	channel.resetReaderToConfirmed()
	equal(t, channel.DepthTimestamp(), int64(0))
}
<|endoftext|>


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

// +build !windows

package gps

import (
	"bytes"
	"context"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

type cmd struct {
	// ctx is provided by the caller; SIGINT is sent when it is cancelled.
	ctx context.Context
	// cancel is called when the graceful shutdown timeout expires.
	cancel context.CancelFunc
	Cmd    *exec.Cmd
}

func commandContext(ctx context.Context, name string, arg ...string) cmd {
	// Create a one-off cancellable context for use by the CommandContext, in
	// the event that we have to force a Process.Kill().
	ctx2, cancel := context.WithCancel(context.Background())

	c := cmd{
		Cmd:    exec.CommandContext(ctx2, name, arg...),
		cancel: cancel,
		ctx:    ctx,
	}
	return c
}

// CombinedOutput is like (*os/exec.Cmd).CombinedOutput except that it
// terminates subprocesses gently (via os.Interrupt), but resorts to Kill if
// the subprocess fails to exit after 1 minute.
func (c cmd) CombinedOutput() ([]byte, error) {
	// Adapted from (*os/exec.Cmd).CombinedOutput
	if c.Cmd.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Cmd.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Cmd.Stdout = &b
	c.Cmd.Stderr = &b

	// Force subprocesses into their own process group, rather than being in the
	// same process group as the dep process. Ctrl-C sent from a terminal will
	// send the signal to the entire running process group, so This allows us to
	// directly manage the issuance of signals to subprocesses in that common
	// case.
	c.Cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
		Pgid:    0,
	}

	if err := c.Cmd.Start(); err != nil {
		return nil, err
	}

	// Adapted from (*os/exec.Cmd).Start
	waitDone := make(chan struct{})
	defer close(waitDone)
	go func() {
		select {
		case <-c.ctx.Done():
			if err := c.Cmd.Process.Signal(os.Interrupt); err != nil {
				// If an error comes back from attempting to signal, proceed
				// immediately to hard kill.
				c.cancel()
			} else {
				stopCancel := time.AfterFunc(time.Minute, c.cancel).Stop
				<-waitDone
				stopCancel()
			}
		case <-waitDone:
		}
	}()

	if err := c.Cmd.Wait(); err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}
<commit_msg>gps: Set pgroup controls in cmd constructor<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build !windows

package gps

import (
	"bytes"
	"context"
	"os"
	"os/exec"
	"syscall"
	"time"

	"github.com/pkg/errors"
)

type cmd struct {
	// ctx is provided by the caller; SIGINT is sent when it is cancelled.
	ctx context.Context
	// cancel is called when the graceful shutdown timeout expires.
	cancel context.CancelFunc
	Cmd    *exec.Cmd
}

func commandContext(ctx context.Context, name string, arg ...string) cmd {
	// Create a one-off cancellable context for use by the CommandContext, in
	// the event that we have to force a Process.Kill().
	ctx2, cancel := context.WithCancel(context.Background())

	c := cmd{
		Cmd:    exec.CommandContext(ctx2, name, arg...),
		cancel: cancel,
		ctx:    ctx,
	}

	// Force subprocesses into their own process group, rather than being in the
	// same process group as the dep process. Because Ctrl-C sent from a
	// terminal will send the signal to the entire currently running process
	// group, this allows us to directly manage the issuance of signals to
	// subprocesses.
	c.Cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
		Pgid:    0,
	}

	return c
}

// CombinedOutput is like (*os/exec.Cmd).CombinedOutput except that it
// terminates subprocesses gently (via os.Interrupt), but resorts to Kill if
// the subprocess fails to exit after 1 minute.
func (c cmd) CombinedOutput() ([]byte, error) {
	// Adapted from (*os/exec.Cmd).CombinedOutput
	if c.Cmd.Stdout != nil {
		return nil, errors.New("exec: Stdout already set")
	}
	if c.Cmd.Stderr != nil {
		return nil, errors.New("exec: Stderr already set")
	}
	var b bytes.Buffer
	c.Cmd.Stdout = &b
	c.Cmd.Stderr = &b

	if err := c.Cmd.Start(); err != nil {
		return nil, err
	}

	// Adapted from (*os/exec.Cmd).Start
	waitDone := make(chan struct{})
	defer close(waitDone)
	go func() {
		select {
		case <-c.ctx.Done():
			if err := c.Cmd.Process.Signal(os.Interrupt); err != nil {
				// If an error comes back from attempting to signal, proceed
				// immediately to hard kill.
				c.cancel()
			} else {
				stopCancel := time.AfterFunc(time.Minute, c.cancel).Stop
				<-waitDone
				stopCancel()
			}
		case <-waitDone:
		}
	}()

	if err := c.Cmd.Wait(); err != nil {
		return nil, err
	}
	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package tracker

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"code.google.com/p/bencode-go"
)

type httpTracker struct {
	*trackerBase
	client    http.Client
	trackerID string
}

func newHTTPTracker(b *trackerBase) *httpTracker {
	return &httpTracker{
		trackerBase: b,
	}
}

func (t *httpTracker) Announce(transfer Transfer, cancel <-chan struct{}, event <-chan trackerEvent, responseC chan<- []Peer) {
	var nextAnnounce time.Duration = time.Nanosecond // Start immediately.
	for {
		select {
		case <-time.After(nextAnnounce):
			infoHash := transfer.InfoHash()
			q := url.Values{}
			q.Set("info_hash", string(infoHash[:]))
			q.Set("peer_id", string(t.peerID[:]))
			q.Set("port", strconv.FormatUint(uint64(t.port), 10))
			q.Set("uploaded", strconv.FormatInt(transfer.Uploaded(), 10))
			q.Set("downloaded", strconv.FormatInt(transfer.Downloaded(), 10))
			q.Set("left", strconv.FormatInt(transfer.Left(), 10))
			q.Set("compact", "1")
			q.Set("no_peer_id", "1")
			q.Set("numwant", strconv.Itoa(NumWant))
			if t.trackerID != "" {
				q.Set("trackerid", t.trackerID)
			}
			u := t.url
			u.RawQuery = q.Encode()
			t.log.Debugf("u.String(): %q", u.String())

			resp, err := t.client.Get(u.String())
			if err != nil {
				t.log.Error(err)
				continue
			}

			if resp.StatusCode >= 400 {
				data, _ := ioutil.ReadAll(resp.Body)
				t.log.Errorf("Status: %d Body: %s", resp.StatusCode, string(data))
				resp.Body.Close()
				continue
			}

			var response = new(httpTrackerAnnounceResponse)
			err = bencode.Unmarshal(resp.Body, &response)
			resp.Body.Close()
			if err != nil {
				t.log.Error(err)
				continue
			}

			if response.FailureReason != "" {
				t.log.Error(response.FailureReason)
				continue
			}
			if response.WarningMessage != "" {
				t.log.Warning(response.WarningMessage)
				continue
			}

			nextAnnounce = time.Duration(response.Interval) * time.Second

			if response.TrackerId != "" {
				t.trackerID = response.TrackerId
			}

			peers, err := t.parsePeers(bytes.NewReader([]byte(response.Peers)))
			if err != nil {
				t.log.Error(err)
				continue
			}

			select {
			case responseC <- peers:
			case <-cancel:
				return
			}
		case <-cancel:
			return
		}
	}
}

type httpTrackerAnnounceResponse struct {
	FailureReason  string `bencode:"failure reason"`
	WarningMessage string `bencode:"warning message"`
	Interval       int32  `bencode:"interval"`
	MinInterval    int32  `bencode:"min interval"`
	TrackerId      string `bencode:"tracker id"`
	Complete       int32  `bencode:"complete"`
	Incomplete     int32  `bencode:"incomplete"`
	Peers          string `bencode:"peers"`
	Peers6         string `bencode:"peers6"`
}
<commit_msg>fix tracker http retry<commit_after>package tracker

import (
	"bytes"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"code.google.com/p/bencode-go"
)

type httpTracker struct {
	*trackerBase
	client    http.Client
	trackerID string
}

func newHTTPTracker(b *trackerBase) *httpTracker {
	return &httpTracker{
		trackerBase: b,
	}
}

func (t *httpTracker) Announce(transfer Transfer, cancel <-chan struct{}, event <-chan trackerEvent, responseC chan<- []Peer) {
	var nextAnnounce time.Duration = time.Nanosecond // Start immediately.
	for {
		select {
		case <-time.After(nextAnnounce):
			// If any error happens before parsing the response, try again in a minute.
			nextAnnounce = time.Minute

			infoHash := transfer.InfoHash()
			q := url.Values{}
			q.Set("info_hash", string(infoHash[:]))
			q.Set("peer_id", string(t.peerID[:]))
			q.Set("port", strconv.FormatUint(uint64(t.port), 10))
			q.Set("uploaded", strconv.FormatInt(transfer.Uploaded(), 10))
			q.Set("downloaded", strconv.FormatInt(transfer.Downloaded(), 10))
			q.Set("left", strconv.FormatInt(transfer.Left(), 10))
			q.Set("compact", "1")
			q.Set("no_peer_id", "1")
			q.Set("numwant", strconv.Itoa(NumWant))
			if t.trackerID != "" {
				q.Set("trackerid", t.trackerID)
			}
			u := t.url
			u.RawQuery = q.Encode()
			t.log.Debugf("u.String(): %q", u.String())

			resp, err := t.client.Get(u.String())
			if err != nil {
				t.log.Error(err)
				continue
			}

			if resp.StatusCode >= 400 {
				data, _ := ioutil.ReadAll(resp.Body)
				t.log.Errorf("Status: %d Body: %s", resp.StatusCode, string(data))
				resp.Body.Close()
				continue
			}

			var response = new(httpTrackerAnnounceResponse)
			err = bencode.Unmarshal(resp.Body, &response)
			resp.Body.Close()
			if err != nil {
				t.log.Error(err)
				continue
			}

			if response.FailureReason != "" {
				t.log.Error(response.FailureReason)
				continue
			}
			if response.WarningMessage != "" {
				t.log.Warning(response.WarningMessage)
				continue
			}

			nextAnnounce = time.Duration(response.Interval) * time.Second

			if response.TrackerId != "" {
				t.trackerID = response.TrackerId
			}

			peers, err := t.parsePeers(bytes.NewReader([]byte(response.Peers)))
			if err != nil {
				t.log.Error(err)
				continue
			}

			select {
			case responseC <- peers:
			case <-cancel:
				return
			}
		case <-cancel:
			return
		}
	}
}

type httpTrackerAnnounceResponse struct {
	FailureReason  string `bencode:"failure reason"`
	WarningMessage string `bencode:"warning message"`
	Interval       int32  `bencode:"interval"`
	MinInterval    int32  `bencode:"min interval"`
	TrackerId      string `bencode:"tracker id"`
	Complete       int32  `bencode:"complete"`
	Incomplete     int32  `bencode:"incomplete"`
	Peers          string `bencode:"peers"`
	Peers6         string `bencode:"peers6"`
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// 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
//
//     https://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 wire

import (
	"errors"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/types/typeutil"
)

type callKind int

const (
	funcProviderCall callKind = iota
	structProvider
	valueExpr
)

// A call represents a step of an injector function.  It may be either a
// function call or a composite struct literal, depending on the value
// of kind.
type call struct {
	// kind indicates the code pattern to use.
	kind callKind

	// out is the type this step produces.
	out types.Type

	// importPath and name identify the provider to call for kind ==
	// funcProviderCall or the type to construct for kind ==
	// structProvider.
	importPath string
	name       string

	// args is a list of arguments to call the provider with.  Each element is:
	// a) one of the givens (args[i] < len(given)), or
	// b) the result of a previous provider call (args[i] >= len(given))
	//
	// This will be nil for kind == valueExpr.
	args []int

	// fieldNames maps the arguments to struct field names.
	// This will only be set if kind == structProvider.
	fieldNames []string

	// ins is the list of types this call receives as arguments.
	// This will be nil for kind == valueExpr.
	ins []types.Type

	// The following are only set for kind == funcProviderCall:

	// hasCleanup is true if the provider call returns a cleanup function.
	hasCleanup bool
	// hasErr is true if the provider call returns an error.
	hasErr bool

	// The following are only set for kind == valueExpr:

	valueExpr     ast.Expr
	valueTypeInfo *types.Info
}

// solve finds the sequence of calls required to produce an output type
// with an optional set of provided inputs.
func solve(fset *token.FileSet, out types.Type, given []types.Type, set *ProviderSet) ([]call, error) {
	for i, g := range given {
		for _, h := range given[:i] {
			if types.Identical(g, h) {
				return nil, fmt.Errorf("multiple inputs of the same type %s", types.TypeString(g, nil))
			}
		}
	}

	// Start building the mapping of type to local variable of the given type.
	// The first len(given) local variables are the given types.
	index := new(typeutil.Map)
	for i, g := range given {
		if pv := set.For(g); !pv.IsNil() {
			switch {
			case pv.IsProvider():
				return nil, fmt.Errorf("input of %s conflicts with provider %s at %s",
					types.TypeString(g, nil), pv.Provider().Name, fset.Position(pv.Provider().Pos))
			case pv.IsValue():
				return nil, fmt.Errorf("input of %s conflicts with value at %s",
					types.TypeString(g, nil), fset.Position(pv.Value().Pos))
			default:
				panic("unknown return value from ProviderSet.For")
			}
		}
		index.Set(g, i)
	}

	// Topological sort of the directed graph defined by the providers
	// using a depth-first search. Provider set graphs are guaranteed to
	// be acyclic.
	var calls []call
	var visit func(trail []ProviderInput) error
	visit = func(trail []ProviderInput) error {
		typ := trail[len(trail)-1].Type
		if index.At(typ) != nil {
			return nil
		}

		switch pv := set.For(typ); {
		case pv.IsNil():
			if len(trail) == 1 {
				return fmt.Errorf("no provider found for %s (output of injector)", types.TypeString(typ, nil))
			}
			// TODO(light): Give name of provider.
			return fmt.Errorf("no provider found for %s (required by provider of %s)", types.TypeString(typ, nil), types.TypeString(trail[len(trail)-2].Type, nil))
		case pv.IsProvider():
			p := pv.Provider()
			if !types.Identical(p.Out, typ) {
				// Interface binding.  Don't create a call ourselves.
				if err := visit(append(trail, ProviderInput{Type: p.Out})); err != nil {
					return err
				}
				index.Set(typ, index.At(p.Out))
				return nil
			}
			for _, a := range p.Args {
				// TODO(light): This will discard grown trail arrays.
				if err := visit(append(trail, a)); err != nil {
					return err
				}
			}
			args := make([]int, len(p.Args))
			ins := make([]types.Type, len(p.Args))
			for i := range p.Args {
				ins[i] = p.Args[i].Type
				args[i] = index.At(p.Args[i].Type).(int)
			}
			index.Set(typ, len(given)+len(calls))
			kind := funcProviderCall
			if p.IsStruct {
				kind = structProvider
			}
			calls = append(calls, call{
				kind:       kind,
				importPath: p.ImportPath,
				name:       p.Name,
				args:       args,
				fieldNames: p.Fields,
				ins:        ins,
				out:        typ,
				hasCleanup: p.HasCleanup,
				hasErr:     p.HasErr,
			})
		case pv.IsValue():
			v := pv.Value()
			if !types.Identical(v.Out, typ) {
				// Interface binding.  Don't create a call ourselves.
				if err := visit(append(trail, ProviderInput{Type: v.Out})); err != nil {
					return err
				}
				index.Set(typ, index.At(v.Out))
				return nil
			}
			index.Set(typ, len(given)+len(calls))
			calls = append(calls, call{
				kind:          valueExpr,
				out:           typ,
				valueExpr:     v.expr,
				valueTypeInfo: v.info,
			})
		default:
			panic("unknown return value from ProviderSet.For")
		}
		return nil
	}
	if err := visit([]ProviderInput{{Type: out}}); err != nil {
		return nil, err
	}
	return calls, nil
}

// buildProviderMap creates the providerMap field for a given provider set.
// The given provider set's providerMap field is ignored.
func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *ProviderSet) (*typeutil.Map, error) {
	providerMap := new(typeutil.Map)
	providerMap.SetHasher(hasher)
	setMap := new(typeutil.Map) // to *ProviderSet, for error messages
	setMap.SetHasher(hasher)

	// Process imports first, verifying that there are no conflicts between sets.
	for _, imp := range set.Imports {
		for _, k := range imp.providerMap.Keys() {
			if providerMap.At(k) != nil {
				return nil, bindingConflictError(fset, imp.Pos, k, setMap.At(k).(*ProviderSet))
			}
			providerMap.Set(k, imp.providerMap.At(k))
			setMap.Set(k, imp)
		}
	}

	// Process non-binding providers in new set.
	for _, p := range set.Providers {
		if providerMap.At(p.Out) != nil {
			return nil, bindingConflictError(fset, p.Pos, p.Out, setMap.At(p.Out).(*ProviderSet))
		}
		providerMap.Set(p.Out, p)
		setMap.Set(p.Out, set)
	}
	for _, v := range set.Values {
		if providerMap.At(v.Out) != nil {
			return nil, bindingConflictError(fset, v.Pos, v.Out, setMap.At(v.Out).(*ProviderSet))
		}
		providerMap.Set(v.Out, v)
		setMap.Set(v.Out, set)
	}

	// Process bindings in set. Must happen after the other providers to
	// ensure the concrete type is being provided.
	for _, b := range set.Bindings {
		if providerMap.At(b.Iface) != nil {
			return nil, bindingConflictError(fset, b.Pos, b.Iface, setMap.At(b.Iface).(*ProviderSet))
		}
		concrete := providerMap.At(b.Provided)
		if concrete == nil {
			pos := fset.Position(b.Pos)
			typ := types.TypeString(b.Provided, nil)
			return nil, fmt.Errorf("%v: no binding for %s", pos, typ)
		}
		providerMap.Set(b.Iface, concrete)
		setMap.Set(b.Iface, set)
	}
	return providerMap, nil
}

func verifyAcyclic(providerMap *typeutil.Map, hasher typeutil.Hasher) error {
	// We must visit every provider type inside provider map, but we don't
	// have a well-defined starting point and there may be several
	// distinct graphs. Thus, we start a depth-first search at every
	// provider, but keep a shared record of visited providers to avoid
	// duplicating work.
	visited := new(typeutil.Map) // to bool
	visited.SetHasher(hasher)
	for _, root := range providerMap.Keys() {
		// Depth-first search using a stack of trails through the provider map.
		stk := [][]types.Type{{root}}
		for len(stk) > 0 {
			curr := stk[len(stk)-1]
			stk = stk[:len(stk)-1]
			head := curr[len(curr)-1]
			if v, _ := visited.At(head).(bool); v {
				continue
			}
			visited.Set(head, true)
			switch x := providerMap.At(head).(type) {
			case nil:
				// Leaf: input.
			case *Value:
				// Leaf: values do not have dependencies.
			case *Provider:
				for _, arg := range x.Args {
					a := arg.Type
					for i, b := range curr {
						if types.Identical(a, b) {
							sb := new(strings.Builder)
							fmt.Fprintf(sb, "cycle for %s:\n", types.TypeString(a, nil))
							for j := i; j < len(curr); j++ {
								p := providerMap.At(curr[j]).(*Provider)
								fmt.Fprintf(sb, "%s (%s.%s) ->\n", types.TypeString(curr[j], nil), p.ImportPath, p.Name)
							}
							fmt.Fprintf(sb, "%s\n", types.TypeString(a, nil))
							return errors.New(sb.String())
						}
					}
					next := append(append([]types.Type(nil), curr...), a)
					stk = append(stk, next)
				}
			default:
				panic("invalid provider map value")
			}
		}
	}
	return nil
}

// bindingConflictError creates a new error describing multiple bindings
// for the same output type.
func bindingConflictError(fset *token.FileSet, pos token.Pos, typ types.Type, prevSet *ProviderSet) error {
	position := fset.Position(pos)
	typString := types.TypeString(typ, nil)
	if prevSet.Name == "" {
		prevPosition := fset.Position(prevSet.Pos)
		return fmt.Errorf("%v: multiple bindings for %s (previous binding at %v)",
			position, typString, prevPosition)
	}
	return fmt.Errorf("%v: multiple bindings for %s (previous binding in %q.%s)",
		position, typString, prevSet.PkgPath, prevSet.Name)
}
<commit_msg>wire: make solver iterative instead of recursive (google/go-cloud#137)<commit_after>// Copyright 2018 Google LLC
//
// 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
//
//     https://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 wire

import (
	"errors"
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/types/typeutil"
)

type callKind int

const (
	funcProviderCall callKind = iota
	structProvider
	valueExpr
)

// A call represents a step of an injector function.  It may be either a
// function call or a composite struct literal, depending on the value
// of kind.
type call struct {
	// kind indicates the code pattern to use.
	kind callKind

	// out is the type this step produces.
	out types.Type

	// importPath and name identify the provider to call for kind ==
	// funcProviderCall or the type to construct for kind ==
	// structProvider.
	importPath string
	name       string

	// args is a list of arguments to call the provider with.  Each element is:
	// a) one of the givens (args[i] < len(given)), or
	// b) the result of a previous provider call (args[i] >= len(given))
	//
	// This will be nil for kind == valueExpr.
	args []int

	// fieldNames maps the arguments to struct field names.
	// This will only be set if kind == structProvider.
	fieldNames []string

	// ins is the list of types this call receives as arguments.
	// This will be nil for kind == valueExpr.
	ins []types.Type

	// The following are only set for kind == funcProviderCall:

	// hasCleanup is true if the provider call returns a cleanup function.
	hasCleanup bool
	// hasErr is true if the provider call returns an error.
	hasErr bool

	// The following are only set for kind == valueExpr:

	valueExpr     ast.Expr
	valueTypeInfo *types.Info
}

// solve finds the sequence of calls required to produce an output type
// with an optional set of provided inputs.
func solve(fset *token.FileSet, out types.Type, given []types.Type, set *ProviderSet) ([]call, error) {
	for i, g := range given {
		for _, h := range given[:i] {
			if types.Identical(g, h) {
				return nil, fmt.Errorf("multiple inputs of the same type %s", types.TypeString(g, nil))
			}
		}
	}

	// Start building the mapping of type to local variable of the given type.
	// The first len(given) local variables are the given types.
	index := new(typeutil.Map)
	for i, g := range given {
		if pv := set.For(g); !pv.IsNil() {
			switch {
			case pv.IsProvider():
				return nil, fmt.Errorf("input of %s conflicts with provider %s at %s",
					types.TypeString(g, nil), pv.Provider().Name, fset.Position(pv.Provider().Pos))
			case pv.IsValue():
				return nil, fmt.Errorf("input of %s conflicts with value at %s",
					types.TypeString(g, nil), fset.Position(pv.Value().Pos))
			default:
				panic("unknown return value from ProviderSet.For")
			}
		}
		index.Set(g, i)
	}

	// Topological sort of the directed graph defined by the providers
	// using a depth-first search using a stack. Provider set graphs are
	// guaranteed to be acyclic.
	var calls []call
	type frame struct {
		t    types.Type
		from types.Type
	}
	stk := []frame{{t: out}}
	for len(stk) > 0 {
		curr := stk[len(stk)-1]
		stk = stk[:len(stk)-1]
		if index.At(curr.t) != nil {
			continue
		}

		switch pv := set.For(curr.t); {
		case pv.IsNil():
			if curr.from == nil {
				return nil, fmt.Errorf("no provider found for %s (output of injector)", types.TypeString(curr.t, nil))
			}
			// TODO(light): Give name of provider.
			return nil, fmt.Errorf("no provider found for %s (required by provider of %s)", types.TypeString(curr.t, nil), types.TypeString(curr.from, nil))
		case pv.IsProvider():
			p := pv.Provider()
			if !types.Identical(p.Out, curr.t) {
				// Interface binding.  Don't create a call ourselves.
				i := index.At(p.Out)
				if i == nil {
					stk = append(stk, curr, frame{t: p.Out, from: curr.t})
					continue
				}
				index.Set(curr.t, i)
				continue
			}
			// Ensure that all argument types have been visited. If not, push them
			// on the stack in reverse order so that calls are added in argument
			// order.
			visitedArgs := true
			for i := len(p.Args) - 1; i >= 0; i-- {
				a := p.Args[i]
				if index.At(a.Type) == nil {
					if visitedArgs {
						// Make sure to re-visit this type after visiting all arguments.
						stk = append(stk, curr)
						visitedArgs = false
					}
					stk = append(stk, frame{t: a.Type, from: curr.t})
				}
			}
			if !visitedArgs {
				continue
			}
			args := make([]int, len(p.Args))
			ins := make([]types.Type, len(p.Args))
			for i := range p.Args {
				ins[i] = p.Args[i].Type
				args[i] = index.At(p.Args[i].Type).(int)
			}
			index.Set(curr.t, len(given)+len(calls))
			kind := funcProviderCall
			if p.IsStruct {
				kind = structProvider
			}
			calls = append(calls, call{
				kind:       kind,
				importPath: p.ImportPath,
				name:       p.Name,
				args:       args,
				fieldNames: p.Fields,
				ins:        ins,
				out:        curr.t,
				hasCleanup: p.HasCleanup,
				hasErr:     p.HasErr,
			})
		case pv.IsValue():
			v := pv.Value()
			if !types.Identical(v.Out, curr.t) {
				// Interface binding.  Don't create a call ourselves.
				i := index.At(v.Out)
				if i == nil {
					stk = append(stk, curr, frame{t: v.Out, from: curr.t})
					continue
				}
				index.Set(curr.t, i)
				continue
			}
			index.Set(curr.t, len(given)+len(calls))
			calls = append(calls, call{
				kind:          valueExpr,
				out:           curr.t,
				valueExpr:     v.expr,
				valueTypeInfo: v.info,
			})
		default:
			panic("unknown return value from ProviderSet.For")
		}
	}
	return calls, nil
}

// buildProviderMap creates the providerMap field for a given provider set.
// The given provider set's providerMap field is ignored.
func buildProviderMap(fset *token.FileSet, hasher typeutil.Hasher, set *ProviderSet) (*typeutil.Map, error) {
	providerMap := new(typeutil.Map)
	providerMap.SetHasher(hasher)
	setMap := new(typeutil.Map) // to *ProviderSet, for error messages
	setMap.SetHasher(hasher)

	// Process imports first, verifying that there are no conflicts between sets.
	for _, imp := range set.Imports {
		for _, k := range imp.providerMap.Keys() {
			if providerMap.At(k) != nil {
				return nil, bindingConflictError(fset, imp.Pos, k, setMap.At(k).(*ProviderSet))
			}
			providerMap.Set(k, imp.providerMap.At(k))
			setMap.Set(k, imp)
		}
	}

	// Process non-binding providers in new set.
	for _, p := range set.Providers {
		if providerMap.At(p.Out) != nil {
			return nil, bindingConflictError(fset, p.Pos, p.Out, setMap.At(p.Out).(*ProviderSet))
		}
		providerMap.Set(p.Out, p)
		setMap.Set(p.Out, set)
	}
	for _, v := range set.Values {
		if providerMap.At(v.Out) != nil {
			return nil, bindingConflictError(fset, v.Pos, v.Out, setMap.At(v.Out).(*ProviderSet))
		}
		providerMap.Set(v.Out, v)
		setMap.Set(v.Out, set)
	}

	// Process bindings in set. Must happen after the other providers to
	// ensure the concrete type is being provided.
	for _, b := range set.Bindings {
		if providerMap.At(b.Iface) != nil {
			return nil, bindingConflictError(fset, b.Pos, b.Iface, setMap.At(b.Iface).(*ProviderSet))
		}
		concrete := providerMap.At(b.Provided)
		if concrete == nil {
			pos := fset.Position(b.Pos)
			typ := types.TypeString(b.Provided, nil)
			return nil, fmt.Errorf("%v: no binding for %s", pos, typ)
		}
		providerMap.Set(b.Iface, concrete)
		setMap.Set(b.Iface, set)
	}
	return providerMap, nil
}

func verifyAcyclic(providerMap *typeutil.Map, hasher typeutil.Hasher) error {
	// We must visit every provider type inside provider map, but we don't
	// have a well-defined starting point and there may be several
	// distinct graphs. Thus, we start a depth-first search at every
	// provider, but keep a shared record of visited providers to avoid
	// duplicating work.
	visited := new(typeutil.Map) // to bool
	visited.SetHasher(hasher)
	for _, root := range providerMap.Keys() {
		// Depth-first search using a stack of trails through the provider map.
		stk := [][]types.Type{{root}}
		for len(stk) > 0 {
			curr := stk[len(stk)-1]
			stk = stk[:len(stk)-1]
			head := curr[len(curr)-1]
			if v, _ := visited.At(head).(bool); v {
				continue
			}
			visited.Set(head, true)
			switch x := providerMap.At(head).(type) {
			case nil:
				// Leaf: input.
			case *Value:
				// Leaf: values do not have dependencies.
			case *Provider:
				for _, arg := range x.Args {
					a := arg.Type
					for i, b := range curr {
						if types.Identical(a, b) {
							sb := new(strings.Builder)
							fmt.Fprintf(sb, "cycle for %s:\n", types.TypeString(a, nil))
							for j := i; j < len(curr); j++ {
								p := providerMap.At(curr[j]).(*Provider)
								fmt.Fprintf(sb, "%s (%s.%s) ->\n", types.TypeString(curr[j], nil), p.ImportPath, p.Name)
							}
							fmt.Fprintf(sb, "%s\n", types.TypeString(a, nil))
							return errors.New(sb.String())
						}
					}
					next := append(append([]types.Type(nil), curr...), a)
					stk = append(stk, next)
				}
			default:
				panic("invalid provider map value")
			}
		}
	}
	return nil
}

// bindingConflictError creates a new error describing multiple bindings
// for the same output type.
func bindingConflictError(fset *token.FileSet, pos token.Pos, typ types.Type, prevSet *ProviderSet) error {
	position := fset.Position(pos)
	typString := types.TypeString(typ, nil)
	if prevSet.Name == "" {
		prevPosition := fset.Position(prevSet.Pos)
		return fmt.Errorf("%v: multiple bindings for %s (previous binding at %v)",
			position, typString, prevPosition)
	}
	return fmt.Errorf("%v: multiple bindings for %s (previous binding in %q.%s)",
		position, typString, prevSet.PkgPath, prevSet.Name)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/BluntSporks/calculation"
	"github.com/BluntSporks/readability"
	"io/ioutil"
	"log"
)

func main() {
	file := flag.String("file", "", "Name of file to filter")
	flag.Parse()

	// Check arguments.
	if *file == "" {
		log.Fatal("Missing -file argument")
	}

	bytes, err := ioutil.ReadFile(*file)
	if err != nil {
		log.Fatal(err)
	}
	text := string(bytes)

	// Score ARI.
	ariScore := read.Ari(text)
	fmt.Printf("Automated Readability: %0.2f\n", ariScore)

	// Score CLI.
	cliScore := read.Cli(text)
	fmt.Printf("Coleman-Liau: %0.2f\n", cliScore)

	// Score Flesch-Kincaid.
	fkScore := read.Fk(text)
	fmt.Printf("Flesch-Kincaid: %0.2f\n", fkScore)

	// Score Gunning fog.
	gfiScore := read.Gfi(text)
	fmt.Printf("Gunning fog: %0.2f\n", gfiScore)

	// Score SMOG.
	smogScore := read.Smog(text)
	fmt.Printf("SMOG: %0.2f\n", smogScore)

	// Yield average score.
	values := []float64{ariScore, cliScore, fkScore, gfiScore, smogScore}
	avg := calc.Mean(values)
	fmt.Printf("Average score: %0.2f\n", avg)
}
<commit_msg>Removing -f flag<commit_after>package main

import (
	"fmt"
	"github.com/BluntSporks/calculation"
	"github.com/BluntSporks/readability"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	// Check arguments.
	if len(os.Args) == 1 {
		log.Fatal("Missing filename argument")
	}

	bytes, err := ioutil.ReadFile(os.Args[1])
	if err != nil {
		log.Fatal(err)
	}
	text := string(bytes)

	// Score ARI.
	ariScore := read.Ari(text)
	fmt.Printf("Automated Readability: %0.2f\n", ariScore)

	// Score CLI.
	cliScore := read.Cli(text)
	fmt.Printf("Coleman-Liau: %0.2f\n", cliScore)

	// Score Flesch-Kincaid.
	fkScore := read.Fk(text)
	fmt.Printf("Flesch-Kincaid: %0.2f\n", fkScore)

	// Score Gunning fog.
	gfiScore := read.Gfi(text)
	fmt.Printf("Gunning fog: %0.2f\n", gfiScore)

	// Score SMOG.
	smogScore := read.Smog(text)
	fmt.Printf("SMOG: %0.2f\n", smogScore)

	// Yield average score.
	values := []float64{ariScore, cliScore, fkScore, gfiScore, smogScore}
	avg := calc.Mean(values)
	fmt.Printf("Average score: %0.2f\n", avg)
}
<|endoftext|>


<commit_before>package guard

import (
	"math/rand"
	"sync/atomic"
	"time"
)

// BackoffStrategy is a backoff strategy.
type BackoffStrategy interface {
	// NextInterval returns the next interval.
	NextInterval() time.Duration

	// Reset creates the clone of the current strategy with initialized state.
	Reset() BackoffStrategy
}

// ConstantBackoff creates BackoffStrategy with constant interval.
// NextInterval() always returns given parameter d.
func ConstantBackoff(d time.Duration) BackoffStrategy {
	return &constantBackoff{d}
}

type constantBackoff struct {
	Interval time.Duration
}

func (c *constantBackoff) NextInterval() time.Duration {
	return c.Interval
}

func (c *constantBackoff) Reset() BackoffStrategy {
	return c
}

// NoBackoff creates BackoffStrategy without interval.
// NextInterval() always returns 0.
func NoBackoff() BackoffStrategy {
	return noBackoff{}
}

type noBackoff struct{}

func (n noBackoff) NextInterval() time.Duration {
	return 0
}

func (n noBackoff) Reset() BackoffStrategy {
	return n
}

// ExponentialBackoff creates BackoffStrategy with exponential backoff.
//
// Let N be a retry count of the process, the value of NextInterval(N) is calculated by following formula.
//
//  NextInterval(N) = BaseInterval(N) * [1-RandomizationFactor, 1+RandomizationFactor)
//  BaseInterval(N) = min(BaseInterval(N-1) * Multiplier, MaxInterval)
//
// The default parameters.
//
//  InitialInterval:     200 (ms)
//  MaxInterval:         1 (min)
//  Multiplier:          2
//  RandomizationFactor: 0.2
//  Randomizer:          rand.New(rand.NewSource(time.Now().Unix()))
//
// Example intervals.
//
//  +----+----------------------+----------------------+
//  | N  | BaseInterval(N) (ms) | NextInterval(N) (ms) |
//  +----+----------------------+----------------------+
//  |  1 |                  200 | [160, 240)           |
//  |  2 |                  400 | [320, 480)           |
//  |  3 |                  800 | [640, 960)           |
//  |  4 |                 1600 | [1280, 1920)         |
//  |  5 |                 3200 | [2560, 3840)         |
//  |  6 |                 6400 | [5120, 7680)         |
//  |  7 |                12800 | [10240, 15360)       |
//  |  8 |                25600 | [20480, 30720)       |
//  |  9 |                51200 | [40960, 61440)       |
//  | 10 |                60000 | [48000, 72000)       |
//  | 11 |                60000 | [48000, 72000)       |
//  +----+----------------------+----------------------+
//
// Note: MaxInterval effects only the base interval.
// The actual interval may exceed MaxInterval depengind on RandomizationFactor.
func ExponentialBackoff(options ...ExponentialBackoffOption) BackoffStrategy {
	e := &exponentialBackoff{
		initialInterval:     float64(200 * time.Millisecond),
		maxInterval:         float64(time.Minute),
		multiplier:          2,
		randomizationFactor: 0.2,
		retryCount:          0,
	}

	for _, o := range options {
		o(e)
	}

	if e.randomizer == nil {
		e.randomizer = rand.New(rand.NewSource(time.Now().Unix()))
	}

	return e
}

type exponentialBackoff struct {
	initialInterval     float64
	maxInterval         float64
	multiplier          float64
	randomizationFactor float64
	randomizer          Randomizer
	retryCount          int64
}

func (e *exponentialBackoff) NextInterval() time.Duration {
	n := e.retryCount

	interval := e.initialInterval
	for i := int64(0); i < n; i++ {
		interval *= e.multiplier
	}

	if interval > e.maxInterval {
		interval = e.maxInterval
	} else {
		atomic.CompareAndSwapInt64(&e.retryCount, n, n+1)
	}

	rnd := (1 - e.randomizationFactor) + (2 * e.randomizationFactor * e.randomizer.Float64())
	nextBackoff := time.Duration(interval * rnd)

	return nextBackoff
}

func (e *exponentialBackoff) Reset() BackoffStrategy {
	clone := *e
	clone.retryCount = 0
	return &clone
}

// ExponentialBackoffOption is the optional parameter for ExponentialBackoff.
type ExponentialBackoffOption func(*exponentialBackoff)

// WithInitialInterval set the initial interval of ExponentialBackoff.
func WithInitialInterval(d time.Duration) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.initialInterval = float64(d)
	})
}

// WithMaxInterval set the maximum interval of ExponentialBackoff.
func WithMaxInterval(d time.Duration) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.maxInterval = float64(d)
	})
}

// WithMultiplier set the multiplier of ExponentialBackoff.
func WithMultiplier(f float64) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.multiplier = f
	})
}

// WithRandomizationFactor set the randomization factor of ExponentialBackoff.
func WithRandomizationFactor(f float64) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.randomizationFactor = f
	})
}

// WithRandomizer set the randomizer of ExponentialBackoff.
func WithRandomizer(r Randomizer) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.randomizer = r
	})
}
<commit_msg>Use InitialInterval in doc<commit_after>package guard

import (
	"math/rand"
	"sync/atomic"
	"time"
)

// BackoffStrategy is a backoff strategy.
type BackoffStrategy interface {
	// NextInterval returns the next interval.
	NextInterval() time.Duration

	// Reset creates the clone of the current strategy with initialized state.
	Reset() BackoffStrategy
}

// ConstantBackoff creates BackoffStrategy with constant interval.
// NextInterval() always returns given parameter d.
func ConstantBackoff(d time.Duration) BackoffStrategy {
	return &constantBackoff{d}
}

type constantBackoff struct {
	Interval time.Duration
}

func (c *constantBackoff) NextInterval() time.Duration {
	return c.Interval
}

func (c *constantBackoff) Reset() BackoffStrategy {
	return c
}

// NoBackoff creates BackoffStrategy without interval.
// NextInterval() always returns 0.
func NoBackoff() BackoffStrategy {
	return noBackoff{}
}

type noBackoff struct{}

func (n noBackoff) NextInterval() time.Duration {
	return 0
}

func (n noBackoff) Reset() BackoffStrategy {
	return n
}

// ExponentialBackoff creates BackoffStrategy with exponential backoff.
//
// Let N be a retry count of the process, the value of NextInterval(N) is calculated by following formula.
//
//  NextInterval(N) = BaseInterval(N) * [1-RandomizationFactor, 1+RandomizationFactor)
//  BaseInterval(N) = min(BaseInterval(N-1) * Multiplier, MaxInterval)
//  BaseInterval(1) = min(InitialInterval, MaxInterval)
//
// The default parameters.
//
//  InitialInterval:     200 (ms)
//  MaxInterval:         1 (min)
//  Multiplier:          2
//  RandomizationFactor: 0.2
//  Randomizer:          rand.New(rand.NewSource(time.Now().Unix()))
//
// Example intervals.
//
//  +----+----------------------+----------------------+
//  | N  | BaseInterval(N) (ms) | NextInterval(N) (ms) |
//  +----+----------------------+----------------------+
//  |  1 |                  200 | [160, 240)           |
//  |  2 |                  400 | [320, 480)           |
//  |  3 |                  800 | [640, 960)           |
//  |  4 |                 1600 | [1280, 1920)         |
//  |  5 |                 3200 | [2560, 3840)         |
//  |  6 |                 6400 | [5120, 7680)         |
//  |  7 |                12800 | [10240, 15360)       |
//  |  8 |                25600 | [20480, 30720)       |
//  |  9 |                51200 | [40960, 61440)       |
//  | 10 |                60000 | [48000, 72000)       |
//  | 11 |                60000 | [48000, 72000)       |
//  +----+----------------------+----------------------+
//
// Note: MaxInterval effects only the base interval.
// The actual interval may exceed MaxInterval depengind on RandomizationFactor.
func ExponentialBackoff(options ...ExponentialBackoffOption) BackoffStrategy {
	e := &exponentialBackoff{
		initialInterval:     float64(200 * time.Millisecond),
		maxInterval:         float64(time.Minute),
		multiplier:          2,
		randomizationFactor: 0.2,
		retryCount:          0,
	}

	for _, o := range options {
		o(e)
	}

	if e.randomizer == nil {
		e.randomizer = rand.New(rand.NewSource(time.Now().Unix()))
	}

	return e
}

type exponentialBackoff struct {
	initialInterval     float64
	maxInterval         float64
	multiplier          float64
	randomizationFactor float64
	randomizer          Randomizer
	retryCount          int64
}

func (e *exponentialBackoff) NextInterval() time.Duration {
	n := e.retryCount

	interval := e.initialInterval
	for i := int64(0); i < n; i++ {
		interval *= e.multiplier
	}

	if interval > e.maxInterval {
		interval = e.maxInterval
	} else {
		atomic.CompareAndSwapInt64(&e.retryCount, n, n+1)
	}

	rnd := (1 - e.randomizationFactor) + (2 * e.randomizationFactor * e.randomizer.Float64())
	nextBackoff := time.Duration(interval * rnd)

	return nextBackoff
}

func (e *exponentialBackoff) Reset() BackoffStrategy {
	clone := *e
	clone.retryCount = 0
	return &clone
}

// ExponentialBackoffOption is the optional parameter for ExponentialBackoff.
type ExponentialBackoffOption func(*exponentialBackoff)

// WithInitialInterval set the initial interval of ExponentialBackoff.
func WithInitialInterval(d time.Duration) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.initialInterval = float64(d)
	})
}

// WithMaxInterval set the maximum interval of ExponentialBackoff.
func WithMaxInterval(d time.Duration) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.maxInterval = float64(d)
	})
}

// WithMultiplier set the multiplier of ExponentialBackoff.
func WithMultiplier(f float64) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.multiplier = f
	})
}

// WithRandomizationFactor set the randomization factor of ExponentialBackoff.
func WithRandomizationFactor(f float64) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.randomizationFactor = f
	})
}

// WithRandomizer set the randomizer of ExponentialBackoff.
func WithRandomizer(r Randomizer) ExponentialBackoffOption {
	return ExponentialBackoffOption(func(e *exponentialBackoff) {
		e.randomizer = r
	})
}
<|endoftext|>


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

package models

import (
	"crypto/sha256"
	"fmt"
	"time"

	"github.com/apigee/registry/rpc"
	"github.com/apigee/registry/server/names"
	"github.com/golang/protobuf/ptypes"
	"github.com/google/uuid"
	"google.golang.org/protobuf/types/known/fieldmaskpb"
)

// This was originally a boolean but gorm does not correctly update booleans from structs.
// https://stackoverflow.com/questions/56653423/gorm-doesnt-update-boolean-field-to-false
const (
	// NotCurrent indicates that a revision is NOT the current revision of a spec
	NotCurrent = 1
	// IsCurrent indicates that a revision is the current revision of a spec
	IsCurrent = 2
)

// Spec is the storage-side representation of a spec.
type Spec struct {
	Key                string    `datastore:"-" gorm:"primaryKey"`
	Currency           int32     // IsCurrent for the current revision of the spec.
	ProjectID          string    // Uniquely identifies a project.
	ApiID              string    // Uniquely identifies an api within a project.
	VersionID          string    // Uniquely identifies a version within a api.
	SpecID             string    // Uniquely identifies a spec within a version.
	RevisionID         string    // Uniquely identifies a revision of a spec.
	Description        string    // A detailed description.
	CreateTime         time.Time // Creation time.
	RevisionCreateTime time.Time // Revision creation time.
	RevisionUpdateTime time.Time // Time of last change.
	MimeType           string    // Spec format.
	SizeInBytes        int32     // Size of the spec.
	Hash               string    // A hash of the spec.
	FileName           string    // Name of spec file.
	SourceURI          string    // The original source URI of the spec.
	Labels             []byte    `datastore:",noindex"` // Serialized labels.
	Annotations        []byte    `datastore:",noindex"` // Serialized annotations.
}

// NewSpec initializes a new resource.
func NewSpec(name names.Spec, body *rpc.ApiSpec) (spec *Spec, err error) {
	now := time.Now()
	spec = &Spec{
		ProjectID:          name.ProjectID,
		ApiID:              name.ApiID,
		VersionID:          name.VersionID,
		SpecID:             name.SpecID,
		Description:        body.GetDescription(),
		FileName:           body.GetFilename(),
		MimeType:           body.GetMimeType(),
		SourceURI:          body.GetSourceUri(),
		CreateTime:         now,
		RevisionCreateTime: now,
		RevisionUpdateTime: now,
		Currency:           IsCurrent,
		RevisionID:         newRevisionID(),
	}

	spec.Labels, err = bytesForMap(body.GetLabels())
	if err != nil {
		return nil, err
	}

	spec.Annotations, err = bytesForMap(body.GetAnnotations())
	if err != nil {
		return nil, err
	}

	if body.GetContents() != nil {
		spec.SizeInBytes = int32(len(body.GetContents()))
		spec.Hash = hashForBytes(body.GetContents())
	}

	return spec, nil
}

// NewRevision returns a new revision based on the spec.
func (s *Spec) NewRevision() *Spec {
	now := time.Now()
	return &Spec{
		ProjectID:          s.ProjectID,
		ApiID:              s.ApiID,
		VersionID:          s.VersionID,
		SpecID:             s.SpecID,
		Description:        s.Description,
		FileName:           s.FileName,
		MimeType:           s.MimeType,
		SizeInBytes:        s.SizeInBytes,
		Hash:               s.Hash,
		SourceURI:          s.SourceURI,
		CreateTime:         s.CreateTime,
		RevisionCreateTime: now,
		RevisionUpdateTime: now,
		Currency:           IsCurrent,
		RevisionID:         newRevisionID(),
	}
}

// Name returns the resource name of the spec.
func (s *Spec) Name() string {
	return names.Spec{
		ProjectID: s.ProjectID,
		ApiID:     s.ApiID,
		VersionID: s.VersionID,
		SpecID:    s.SpecID,
	}.String()
}

// RevisionName generates the resource name of the spec revision.
func (s *Spec) RevisionName() string {
	return fmt.Sprintf("projects/%s/apis/%s/versions/%s/specs/%s@%s", s.ProjectID, s.ApiID, s.VersionID, s.SpecID, s.RevisionID)
}

// FullMessage returns the full view of the spec resource as an RPC message.
func (s *Spec) FullMessage(blob *Blob, name string) (message *rpc.ApiSpec, err error) {
	message, err = s.BasicMessage(name)
	if err != nil {
		return nil, err
	}

	message.Annotations, err = mapForBytes(s.Annotations)
	if err != nil {
		return nil, err
	}

	message.Contents = blob.Contents
	return message, nil
}

// BasicMessage returns the basic view of the spec resource as an RPC message.
func (s *Spec) BasicMessage(name string) (message *rpc.ApiSpec, err error) {
	message = &rpc.ApiSpec{
		Name:        name,
		Filename:    s.FileName,
		Description: s.Description,
		Hash:        s.Hash,
		SizeBytes:   s.SizeInBytes,
		MimeType:    s.MimeType,
		SourceUri:   s.SourceURI,
		RevisionId:  s.RevisionID,
	}

	message.CreateTime, err = ptypes.TimestampProto(s.CreateTime)
	if err != nil {
		return nil, err
	}

	message.RevisionCreateTime, err = ptypes.TimestampProto(s.RevisionCreateTime)
	if err != nil {
		return nil, err
	}

	message.RevisionUpdateTime, err = ptypes.TimestampProto(s.RevisionUpdateTime)
	if err != nil {
		return nil, err
	}

	message.Labels, err = mapForBytes(s.Labels)
	if err != nil {
		return nil, err
	}

	return message, nil
}

// Update modifies a spec using the contents of a message.
func (s *Spec) Update(message *rpc.ApiSpec, mask *fieldmaskpb.FieldMask) error {
	now := time.Now()
	if activeUpdateMask(mask) {
		for _, field := range mask.Paths {
			switch field {
			case "filename":
				s.FileName = message.GetFilename()
			case "description":
				s.Description = message.GetDescription()
			case "contents":
				contents := message.GetContents()
				// Save some properties of the spec contents.
				// The bytes of the contents are stored in a Blob.
				hash := hashForBytes(contents)
				if s.Hash != hash {
					s.Hash = hash
					s.RevisionID = newRevisionID()
					s.CreateTime = now
				}
				s.SizeInBytes = int32(len(contents))
			case "mime_type":
				s.MimeType = message.GetMimeType()
			case "source_uri":
				s.SourceURI = message.GetSourceUri()
			case "labels":
				var err error
				if s.Labels, err = bytesForMap(message.GetLabels()); err != nil {
					return err
				}
			case "annotations":
				var err error
				if s.Annotations, err = bytesForMap(message.GetAnnotations()); err != nil {
					return err
				}
			}
		}
	} else {
		filename := message.GetFilename()
		if filename != "" {
			s.FileName = filename
		}
		description := message.GetDescription()
		if description != "" {
			s.Description = description
		}
		contents := message.GetContents()
		if contents != nil {
			// Save some properties of the spec contents.
			// The bytes of the contents are stored in a Blob.
			hash := hashForBytes(contents)
			if s.Hash != hash {
				s.Hash = hash
				s.RevisionID = newRevisionID()
				s.RevisionCreateTime = now
			}
			s.SizeInBytes = int32(len(contents))
		}
		mimeType := message.GetMimeType()
		if mimeType != "" {
			s.MimeType = mimeType
		}
		sourceURI := message.GetSourceUri()
		if sourceURI != "" {
			s.SourceURI = sourceURI
		}
		var err error
		if s.Labels, err = bytesForMap(message.GetLabels()); err != nil {
			return err
		}
		if s.Annotations, err = bytesForMap(message.GetAnnotations()); err != nil {
			return err
		}
	}
	s.Currency = IsCurrent
	s.RevisionUpdateTime = now
	return nil
}

// LabelsMap returns a map representation of stored labels.
func (s *Spec) LabelsMap() (map[string]string, error) {
	return mapForBytes(s.Labels)
}

func newRevisionID() string {
	s := uuid.New().String()
	return s[len(s)-8:]
}

func hashForBytes(b []byte) string {
	if len(b) == 0 {
		return ""
	}

	h := sha256.New()
	h.Write(b)
	bs := h.Sum(nil)
	return fmt.Sprintf("%x", bs)
}

// SpecRevisionTag is the storage-side representation of a spec revision tag.
type SpecRevisionTag struct {
	Key        string    `datastore:"-" gorm:"primaryKey"`
	ProjectID  string    // Uniquely identifies a project.
	ApiID      string    // Uniquely identifies an api within a project.
	VersionID  string    // Uniquely identifies a version within a api.
	SpecID     string    // Uniquely identifies a spec within a version.
	RevisionID string    // Uniquely identifies a revision of a spec.
	Tag        string    // The tag to use for the revision.
	CreateTime time.Time // Creation time.
	UpdateTime time.Time // Time of last change.
}

// NewSpecRevisionTag initializes a new revision tag from a given revision name and tag string.
func NewSpecRevisionTag(name names.SpecRevision, tag string) *SpecRevisionTag {
	now := time.Now()
	return &SpecRevisionTag{
		ProjectID:  name.ProjectID,
		ApiID:      name.ApiID,
		VersionID:  name.VersionID,
		SpecID:     name.SpecID,
		RevisionID: name.RevisionID,
		Tag:        tag,
		CreateTime: now,
		UpdateTime: now,
	}
}

func (t *SpecRevisionTag) String() string {
	return fmt.Sprintf("projects/%s/apis/%s/versions/%s/specs/%s@%s", t.ProjectID, t.ApiID, t.VersionID, t.SpecID, t.Tag)
}
<commit_msg>Do not change spec create time on update (#120)<commit_after>// Copyright 2020 Google LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package models

import (
	"crypto/sha256"
	"fmt"
	"time"

	"github.com/apigee/registry/rpc"
	"github.com/apigee/registry/server/names"
	"github.com/golang/protobuf/ptypes"
	"github.com/google/uuid"
	"google.golang.org/protobuf/types/known/fieldmaskpb"
)

// This was originally a boolean but gorm does not correctly update booleans from structs.
// https://stackoverflow.com/questions/56653423/gorm-doesnt-update-boolean-field-to-false
const (
	// NotCurrent indicates that a revision is NOT the current revision of a spec
	NotCurrent = 1
	// IsCurrent indicates that a revision is the current revision of a spec
	IsCurrent = 2
)

// Spec is the storage-side representation of a spec.
type Spec struct {
	Key                string    `datastore:"-" gorm:"primaryKey"`
	Currency           int32     // IsCurrent for the current revision of the spec.
	ProjectID          string    // Uniquely identifies a project.
	ApiID              string    // Uniquely identifies an api within a project.
	VersionID          string    // Uniquely identifies a version within a api.
	SpecID             string    // Uniquely identifies a spec within a version.
	RevisionID         string    // Uniquely identifies a revision of a spec.
	Description        string    // A detailed description.
	CreateTime         time.Time // Creation time.
	RevisionCreateTime time.Time // Revision creation time.
	RevisionUpdateTime time.Time // Time of last change.
	MimeType           string    // Spec format.
	SizeInBytes        int32     // Size of the spec.
	Hash               string    // A hash of the spec.
	FileName           string    // Name of spec file.
	SourceURI          string    // The original source URI of the spec.
	Labels             []byte    `datastore:",noindex"` // Serialized labels.
	Annotations        []byte    `datastore:",noindex"` // Serialized annotations.
}

// NewSpec initializes a new resource.
func NewSpec(name names.Spec, body *rpc.ApiSpec) (spec *Spec, err error) {
	now := time.Now()
	spec = &Spec{
		ProjectID:          name.ProjectID,
		ApiID:              name.ApiID,
		VersionID:          name.VersionID,
		SpecID:             name.SpecID,
		Description:        body.GetDescription(),
		FileName:           body.GetFilename(),
		MimeType:           body.GetMimeType(),
		SourceURI:          body.GetSourceUri(),
		CreateTime:         now,
		RevisionCreateTime: now,
		RevisionUpdateTime: now,
		Currency:           IsCurrent,
		RevisionID:         newRevisionID(),
	}

	spec.Labels, err = bytesForMap(body.GetLabels())
	if err != nil {
		return nil, err
	}

	spec.Annotations, err = bytesForMap(body.GetAnnotations())
	if err != nil {
		return nil, err
	}

	if body.GetContents() != nil {
		spec.SizeInBytes = int32(len(body.GetContents()))
		spec.Hash = hashForBytes(body.GetContents())
	}

	return spec, nil
}

// NewRevision returns a new revision based on the spec.
func (s *Spec) NewRevision() *Spec {
	now := time.Now()
	return &Spec{
		ProjectID:          s.ProjectID,
		ApiID:              s.ApiID,
		VersionID:          s.VersionID,
		SpecID:             s.SpecID,
		Description:        s.Description,
		FileName:           s.FileName,
		MimeType:           s.MimeType,
		SizeInBytes:        s.SizeInBytes,
		Hash:               s.Hash,
		SourceURI:          s.SourceURI,
		CreateTime:         s.CreateTime,
		RevisionCreateTime: now,
		RevisionUpdateTime: now,
		Currency:           IsCurrent,
		RevisionID:         newRevisionID(),
	}
}

// Name returns the resource name of the spec.
func (s *Spec) Name() string {
	return names.Spec{
		ProjectID: s.ProjectID,
		ApiID:     s.ApiID,
		VersionID: s.VersionID,
		SpecID:    s.SpecID,
	}.String()
}

// RevisionName generates the resource name of the spec revision.
func (s *Spec) RevisionName() string {
	return fmt.Sprintf("projects/%s/apis/%s/versions/%s/specs/%s@%s", s.ProjectID, s.ApiID, s.VersionID, s.SpecID, s.RevisionID)
}

// FullMessage returns the full view of the spec resource as an RPC message.
func (s *Spec) FullMessage(blob *Blob, name string) (message *rpc.ApiSpec, err error) {
	message, err = s.BasicMessage(name)
	if err != nil {
		return nil, err
	}

	message.Annotations, err = mapForBytes(s.Annotations)
	if err != nil {
		return nil, err
	}

	message.Contents = blob.Contents
	return message, nil
}

// BasicMessage returns the basic view of the spec resource as an RPC message.
func (s *Spec) BasicMessage(name string) (message *rpc.ApiSpec, err error) {
	message = &rpc.ApiSpec{
		Name:        name,
		Filename:    s.FileName,
		Description: s.Description,
		Hash:        s.Hash,
		SizeBytes:   s.SizeInBytes,
		MimeType:    s.MimeType,
		SourceUri:   s.SourceURI,
		RevisionId:  s.RevisionID,
	}

	message.CreateTime, err = ptypes.TimestampProto(s.CreateTime)
	if err != nil {
		return nil, err
	}

	message.RevisionCreateTime, err = ptypes.TimestampProto(s.RevisionCreateTime)
	if err != nil {
		return nil, err
	}

	message.RevisionUpdateTime, err = ptypes.TimestampProto(s.RevisionUpdateTime)
	if err != nil {
		return nil, err
	}

	message.Labels, err = mapForBytes(s.Labels)
	if err != nil {
		return nil, err
	}

	return message, nil
}

// Update modifies a spec using the contents of a message.
func (s *Spec) Update(message *rpc.ApiSpec, mask *fieldmaskpb.FieldMask) error {
	now := time.Now()
	if activeUpdateMask(mask) {
		for _, field := range mask.Paths {
			switch field {
			case "filename":
				s.FileName = message.GetFilename()
			case "description":
				s.Description = message.GetDescription()
			case "contents":
				s.updateContents(message.GetContents())
			case "mime_type":
				s.MimeType = message.GetMimeType()
			case "source_uri":
				s.SourceURI = message.GetSourceUri()
			case "labels":
				var err error
				if s.Labels, err = bytesForMap(message.GetLabels()); err != nil {
					return err
				}
			case "annotations":
				var err error
				if s.Annotations, err = bytesForMap(message.GetAnnotations()); err != nil {
					return err
				}
			}
		}
	} else {
		filename := message.GetFilename()
		if filename != "" {
			s.FileName = filename
		}
		description := message.GetDescription()
		if description != "" {
			s.Description = description
		}
		if contents := message.GetContents(); contents != nil {
			s.updateContents(message.GetContents())
		}
		mimeType := message.GetMimeType()
		if mimeType != "" {
			s.MimeType = mimeType
		}
		sourceURI := message.GetSourceUri()
		if sourceURI != "" {
			s.SourceURI = sourceURI
		}
		var err error
		if s.Labels, err = bytesForMap(message.GetLabels()); err != nil {
			return err
		}
		if s.Annotations, err = bytesForMap(message.GetAnnotations()); err != nil {
			return err
		}
	}
	s.Currency = IsCurrent
	s.RevisionUpdateTime = now
	return nil
}

func (s *Spec) updateContents(contents []byte) {
	if hash := hashForBytes(contents); hash != s.Hash {
		s.Hash = hash
		s.RevisionID = newRevisionID()
		s.SizeInBytes = int32(len(contents))

		now := time.Now()
		s.RevisionCreateTime = now
		s.RevisionUpdateTime = now
	}
}

// LabelsMap returns a map representation of stored labels.
func (s *Spec) LabelsMap() (map[string]string, error) {
	return mapForBytes(s.Labels)
}

func newRevisionID() string {
	s := uuid.New().String()
	return s[len(s)-8:]
}

func hashForBytes(b []byte) string {
	if len(b) == 0 {
		return ""
	}

	h := sha256.New()
	h.Write(b)
	bs := h.Sum(nil)
	return fmt.Sprintf("%x", bs)
}

// SpecRevisionTag is the storage-side representation of a spec revision tag.
type SpecRevisionTag struct {
	Key        string    `datastore:"-" gorm:"primaryKey"`
	ProjectID  string    // Uniquely identifies a project.
	ApiID      string    // Uniquely identifies an api within a project.
	VersionID  string    // Uniquely identifies a version within a api.
	SpecID     string    // Uniquely identifies a spec within a version.
	RevisionID string    // Uniquely identifies a revision of a spec.
	Tag        string    // The tag to use for the revision.
	CreateTime time.Time // Creation time.
	UpdateTime time.Time // Time of last change.
}

// NewSpecRevisionTag initializes a new revision tag from a given revision name and tag string.
func NewSpecRevisionTag(name names.SpecRevision, tag string) *SpecRevisionTag {
	now := time.Now()
	return &SpecRevisionTag{
		ProjectID:  name.ProjectID,
		ApiID:      name.ApiID,
		VersionID:  name.VersionID,
		SpecID:     name.SpecID,
		RevisionID: name.RevisionID,
		Tag:        tag,
		CreateTime: now,
		UpdateTime: now,
	}
}

func (t *SpecRevisionTag) String() string {
	return fmt.Sprintf("projects/%s/apis/%s/versions/%s/specs/%s@%s", t.ProjectID, t.ApiID, t.VersionID, t.SpecID, t.Tag)
}
<|endoftext|>