<commit_before>package repl_util

import (
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/replication/source"
	"github.com/chrislusf/seaweedfs/weed/util"
)

func CopyFromChunkViews(chunkViews []*filer.ChunkView, filerSource *source.FilerSource, writeFunc func(data []byte) error) error {

	for _, chunk := range chunkViews {

		fileUrls, err := filerSource.LookupFileId(chunk.FileId)
		if err != nil {
			return err
		}

		var writeErr error
		var shouldRetry bool

		for _, fileUrl := range fileUrls {
			shouldRetry, err = util.ReadUrlAsStream(fileUrl+"?readDeleted=true", nil, false, chunk.IsFullChunk(), chunk.Offset, int(chunk.Size), func(data []byte) {
				writeErr = writeFunc(data)
			})
			if err != nil {
				glog.V(1).Infof("read from %s: %v", fileUrl, err)
			} else if writeErr != nil {
				glog.V(1).Infof("copy from %s: %v", fileUrl, writeErr)
			} else {
				break
			}
		}
		if shouldRetry && err != nil {
			return err
		}
		if writeErr != nil {
			return writeErr
		}
	}
	return nil
}
<commit_msg>revert<commit_after>package repl_util

import (
	"github.com/chrislusf/seaweedfs/weed/filer"
	"github.com/chrislusf/seaweedfs/weed/glog"
	"github.com/chrislusf/seaweedfs/weed/replication/source"
	"github.com/chrislusf/seaweedfs/weed/util"
)

func CopyFromChunkViews(chunkViews []*filer.ChunkView, filerSource *source.FilerSource, writeFunc func(data []byte) error) error {

	for _, chunk := range chunkViews {

		fileUrls, err := filerSource.LookupFileId(chunk.FileId)
		if err != nil {
			return err
		}

		var writeErr error
		var shouldRetry bool

		for _, fileUrl := range fileUrls {
			shouldRetry, err = util.ReadUrlAsStream(fileUrl, nil, false, chunk.IsFullChunk(), chunk.Offset, int(chunk.Size), func(data []byte) {
				writeErr = writeFunc(data)
			})
			if err != nil {
				glog.V(1).Infof("read from %s: %v", fileUrl, err)
			} else if writeErr != nil {
				glog.V(1).Infof("copy from %s: %v", fileUrl, writeErr)
			} else {
				break
			}
		}
		if shouldRetry && err != nil {
			return err
		}
		if writeErr != nil {
			return writeErr
		}
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/juju/cmd"
	"github.com/juju/errors"

	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/cmd/juju/common"
	"github.com/juju/juju/jujuclient"
)

type cloudList struct {
	public   []string
	builtin  []string
	personal []string
}

func formatCloudDetailsTabular(clouds cloudList, credStore jujuclient.CredentialStore) ([]byte, error) {
	var out bytes.Buffer
	const (
		// To format things into columns.
		minwidth = 0
		tabwidth = 1
		padding  = 2
		padchar  = ' '
		flags    = 0
	)
	tw := tabwriter.NewWriter(&out, minwidth, tabwidth, padding, padchar, flags)
	p := func(values ...string) {
		text := strings.Join(values, "\t")
		fmt.Fprintln(tw, text)
	}
	p("Cloud\tCredentials\tDefault Region")
	printClouds := func(cloudNames []string) error {
		sort.Strings(cloudNames)
		for _, name := range cloudNames {
			cred, err := credStore.CredentialForCloud(name)
			if err != nil && !errors.IsNotFound(err) {
				return errors.Annotatef(err, "error loading credential for cloud %q", name)
			}
			if err != nil || len(cred.AuthCredentials) == 0 {
				p(name, "", "")
				continue
			}
			var sortedCredNames []string
			for credName := range cred.AuthCredentials {
				sortedCredNames = append(sortedCredNames, credName)
			}
			sort.Strings(sortedCredNames)
			i := 0
			for _, credName := range sortedCredNames {
				if i == 0 {
					p(name, credName, cred.DefaultRegion)
				} else {
					p("", credName, "")
				}
				i++
			}
		}
		return nil
	}
	if err := printClouds(clouds.public); err != nil {
		return nil, err
	}
	if err := printClouds(clouds.builtin); err != nil {
		return nil, err
	}
	if err := printClouds(clouds.personal); err != nil {
		return nil, err
	}

	tw.Flush()
	return out.Bytes(), nil
}

func printClouds(ctx *cmd.Context, credStore jujuclient.CredentialStore) error {
	publicClouds, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
	if err != nil {
		return err
	}

	personalClouds, err := jujucloud.PersonalCloudMetadata()
	if err != nil {
		return err
	}

	fmt.Fprintln(ctx.Stdout, "You can bootstrap on these clouds. See ‘--regions <cloud>’ for all regions.")
	clouds := cloudList{}
	for name := range publicClouds {
		clouds.public = append(clouds.public, name)
	}
	// Add in built in clouds like localhost (lxd).
	for name := range common.BuiltInClouds() {
		clouds.builtin = append(clouds.builtin, name)
	}
	for name := range personalClouds {
		clouds.personal = append(clouds.personal, name)
	}
	out, err := formatCloudDetailsTabular(clouds, credStore)
	if err != nil {
		return err
	}
	fmt.Fprintln(ctx.Stdout, string(out))
	credHelpText := `
You will need to have a credential if you want to bootstrap on a cloud, see
‘juju autoload-credentials’ and ‘juju add-credential’. The first credential
listed is the default. Add more clouds with ‘juju add-cloud’.
`
	fmt.Fprintf(ctx.Stdout, credHelpText[1:])
	return nil
}

func printCloudRegions(ctx *cmd.Context, cloudName string) error {
	cloud, err := jujucloud.CloudByName(cloudName)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Showing regions for %s:\n", cloudName)
	for _, region := range cloud.Regions {
		fmt.Fprintln(ctx.Stdout, region.Name)
	}
	return nil
}
<commit_msg>Tweak<commit_after>// Copyright 2016 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

import (
	"bytes"
	"fmt"
	"sort"
	"strings"
	"text/tabwriter"

	"github.com/juju/cmd"
	"github.com/juju/errors"

	jujucloud "github.com/juju/juju/cloud"
	"github.com/juju/juju/cmd/juju/common"
	"github.com/juju/juju/jujuclient"
)

type cloudList struct {
	public   []string
	builtin  []string
	personal []string
}

func formatCloudDetailsTabular(clouds cloudList, credStore jujuclient.CredentialStore) ([]byte, error) {
	var out bytes.Buffer
	const (
		// To format things into columns.
		minwidth = 0
		tabwidth = 1
		padding  = 2
		padchar  = ' '
		flags    = 0
	)
	tw := tabwriter.NewWriter(&out, minwidth, tabwidth, padding, padchar, flags)
	p := func(values ...string) {
		text := strings.Join(values, "\t")
		fmt.Fprintln(tw, text)
	}
	p("Cloud\tCredentials\tDefault Region")
	printClouds := func(cloudNames []string) error {
		sort.Strings(cloudNames)
		for _, name := range cloudNames {
			cred, err := credStore.CredentialForCloud(name)
			if err != nil && !errors.IsNotFound(err) {
				return errors.Annotatef(err, "error loading credential for cloud %q", name)
			}
			if err != nil || len(cred.AuthCredentials) == 0 {
				p(name, "", "")
				continue
			}
			var sortedCredNames []string
			for credName := range cred.AuthCredentials {
				sortedCredNames = append(sortedCredNames, credName)
			}
			sort.Strings(sortedCredNames)
			for i, credName := range sortedCredNames {
				if i == 0 {
					p(name, credName, cred.DefaultRegion)
				} else {
					p("", credName, "")
				}
				i++
			}
		}
		return nil
	}
	if err := printClouds(clouds.public); err != nil {
		return nil, err
	}
	if err := printClouds(clouds.builtin); err != nil {
		return nil, err
	}
	if err := printClouds(clouds.personal); err != nil {
		return nil, err
	}

	tw.Flush()
	return out.Bytes(), nil
}

func printClouds(ctx *cmd.Context, credStore jujuclient.CredentialStore) error {
	publicClouds, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
	if err != nil {
		return err
	}

	personalClouds, err := jujucloud.PersonalCloudMetadata()
	if err != nil {
		return err
	}

	fmt.Fprintln(ctx.Stdout, "You can bootstrap on these clouds. See ‘--regions <cloud>’ for all regions.")
	clouds := cloudList{}
	for name := range publicClouds {
		clouds.public = append(clouds.public, name)
	}
	// Add in built in clouds like localhost (lxd).
	for name := range common.BuiltInClouds() {
		clouds.builtin = append(clouds.builtin, name)
	}
	for name := range personalClouds {
		clouds.personal = append(clouds.personal, name)
	}
	out, err := formatCloudDetailsTabular(clouds, credStore)
	if err != nil {
		return err
	}
	fmt.Fprintln(ctx.Stdout, string(out))
	credHelpText := `
You will need to have a credential if you want to bootstrap on a cloud, see
‘juju autoload-credentials’ and ‘juju add-credential’. The first credential
listed is the default. Add more clouds with ‘juju add-cloud’.
`
	fmt.Fprintf(ctx.Stdout, credHelpText[1:])
	return nil
}

func printCloudRegions(ctx *cmd.Context, cloudName string) error {
	cloud, err := jujucloud.CloudByName(cloudName)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Showing regions for %s:\n", cloudName)
	for _, region := range cloud.Regions {
		fmt.Fprintln(ctx.Stdout, region.Name)
	}
	return nil
}
<|endoftext|>


<commit_before>package lzma

import (
	"errors"
	"fmt"
	"io"
)

// Decoder decodes a raw LZMA stream without any header.
type Decoder struct {
	// dictionary; the rear pointer of the buffer will be used for
	// reading the data.
	Dict *DecoderDict
	// decoder state
	State *State
	// range decoder
	rd *rangeDecoder
	// start stores the head value of the dictionary for the LZMA
	// stream
	start int64
	// size of uncompressed data
	size int64
	// eos found
	eos bool
}

// NewDecoder creates a new decoder value. The parameter size provides
// the expected byte size of the decompressed data. If the size is
// unknown use a negative value. In that case the decoder will look for
// a terminating end-of-stream marker.
func NewDecoder(br io.ByteReader, state *State, dict *DecoderDict, size int64) (d *Decoder, err error) {
	rd, err := newRangeDecoder(br)
	if err != nil {
		return nil, err
	}
	d = &Decoder{
		State: state,
		Dict:  dict,
		rd:    rd,
		size:  size,
		start: dict.Pos(),
	}
	return d, nil
}

// Reopens the decoder with a new byte reader and a new size. Reopen
// resets the Decompressed counter to zero.
func (d *Decoder) Reopen(br io.ByteReader, size int64) error {
	var err error
	if d.rd, err = newRangeDecoder(br); err != nil {
		return err
	}
	d.start = d.Dict.Pos()
	d.size = size
	return nil
}

// decodeLiteral decodes a single literal from the LZMA stream.
func (d *Decoder) decodeLiteral() (op operation, err error) {
	litState := d.State.litState(d.Dict.ByteAt(1), d.Dict.head)
	match := d.Dict.ByteAt(int(d.State.rep[0]) + 1)
	s, err := d.State.litCodec.Decode(d.rd, d.State.state, match, litState)
	if err != nil {
		return nil, err
	}
	return lit{s}, nil
}

// errEOS indicates that an EOS marker has been found.
var errEOS = errors.New("EOS marker found")

// readOp decodes the next operation from the compressed stream. It
// returns the operation. If an explicit end of stream marker is
// identified the eos error is returned.
func (d *Decoder) readOp() (op operation, err error) {
	// Value of the end of stream (EOS) marker
	const eosDist = 1<<32 - 1

	state, state2, posState := d.State.states(d.Dict.head)

	b, err := d.State.isMatch[state2].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// literal
		op, err := d.decodeLiteral()
		if err != nil {
			return nil, err
		}
		d.State.updateStateLiteral()
		return op, nil
	}
	b, err = d.State.isRep[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// simple match
		d.State.rep[3], d.State.rep[2], d.State.rep[1] =
			d.State.rep[2], d.State.rep[1], d.State.rep[0]

		d.State.updateStateMatch()
		// The length decoder returns the length offset.
		n, err := d.State.lenCodec.Decode(d.rd, posState)
		if err != nil {
			return nil, err
		}
		// The dist decoder returns the distance offset. The actual
		// distance is 1 higher.
		d.State.rep[0], err = d.State.distCodec.Decode(d.rd, n)
		if err != nil {
			return nil, err
		}
		if d.State.rep[0] == eosDist {
			return nil, errEOS
		}
		op = match{n: int(n) + minMatchLen,
			distance: int(d.State.rep[0]) + minDistance}
		return op, nil
	}
	b, err = d.State.isRepG0[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	dist := d.State.rep[0]
	if b == 0 {
		// rep match 0
		b, err = d.State.isRepG0Long[state2].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			d.State.updateStateShortRep()
			op = match{n: 1, distance: int(dist) + minDistance}
			return op, nil
		}
	} else {
		b, err = d.State.isRepG1[state].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			dist = d.State.rep[1]
		} else {
			b, err = d.State.isRepG2[state].Decode(d.rd)
			if err != nil {
				return nil, err
			}
			if b == 0 {
				dist = d.State.rep[2]
			} else {
				dist = d.State.rep[3]
				d.State.rep[3] = d.State.rep[2]
			}
			d.State.rep[2] = d.State.rep[1]
		}
		d.State.rep[1] = d.State.rep[0]
		d.State.rep[0] = dist
	}
	n, err := d.State.repLenCodec.Decode(d.rd, posState)
	if err != nil {
		return nil, err
	}
	d.State.updateStateRep()
	op = match{n: int(n) + minMatchLen, distance: int(dist) + minDistance}
	return op, nil
}

// apply takes the operation and transforms the decoder dictionary accordingly.
func (d *Decoder) apply(op operation) error {
	switch x := op.(type) {
	case match:
		return d.Dict.WriteMatch(x.distance, x.n)
	case lit:
		return d.Dict.WriteByte(x.b)
	}
	panic("op is neither a match nor a literal")
}

// Decompress fills the dictionary unless no space for new data is
// available. If the end of the LZMA stream has been reached io.EOF will
// be returned.
func (d *Decoder) Decompress() (n int, err error) {
	if d.eos {
		return 0, io.EOF
	}
	for d.Dict.Available() >= maxMatchLen {
		op, err := d.readOp()
		switch err {
		case nil:
			break
		case errEOS:
			d.eos = true
			if !d.rd.possiblyAtEnd() {
				return n, errDataAfterEOS
			}
			if d.size >= 0 && d.size != d.Decompressed() {
				return n, errSize
			}
			return n, io.EOF
		case io.EOF:
			d.eos = true
			return n, io.ErrUnexpectedEOF
		default:
			return n, err
		}
		if err = d.apply(op); err != nil {
			return n, err
		}
		n += op.Len()
		if d.size >= 0 && d.Decompressed() >= d.size {
			d.eos = true
			if d.Decompressed() > d.size {
				return n, errSize
			}
			if !d.rd.possiblyAtEnd() {
				switch _, err = d.readOp(); err {
				case nil:
					return n, errSize
				case io.EOF:
					return n, io.ErrUnexpectedEOF
				case errEOS:
					break
				default:
					return n, err
				}
			}
			return n, io.EOF
		}
	}
	return n, nil
}

// Errors that may be returned while decoding data.
var (
	errDataAfterEOS = errors.New("lzma: data after end of stream marker")
	errSize         = errors.New("lzma: wrong uncompressed data size")
)

// Read reads data from the buffer. If no more data is available io.EOF is
// returned.
func (d *Decoder) Read(p []byte) (n int, err error) {
	var k int
	for {
		// Read of decoder dict never returns an error.
		k, err = d.Dict.Read(p[n:])
		if err != nil {
			panic(fmt.Errorf("dictionary read error %s", err))
		}
		if k == 0 && d.eos {
			return n, io.EOF
		}
		n += k
		if n >= len(p) {
			return n, nil
		}
		if _, err = d.Decompress(); err != nil && err != io.EOF {
			return n, err
		}
	}
}

// Decompressed returns the number of bytes decompressed by the decoder.
func (d *Decoder) Decompressed() int64 {
	return d.Dict.Pos() - d.start
}
<commit_msg>lzma: remove Decompress from the public interface<commit_after>package lzma

import (
	"errors"
	"fmt"
	"io"
)

// Decoder decodes a raw LZMA stream without any header.
type Decoder struct {
	// dictionary; the rear pointer of the buffer will be used for
	// reading the data.
	Dict *DecoderDict
	// decoder state
	State *State
	// range decoder
	rd *rangeDecoder
	// start stores the head value of the dictionary for the LZMA
	// stream
	start int64
	// size of uncompressed data
	size int64
	// eos found
	eos bool
}

// NewDecoder creates a new decoder value. The parameter size provides
// the expected byte size of the decompressed data. If the size is
// unknown use a negative value. In that case the decoder will look for
// a terminating end-of-stream marker.
func NewDecoder(br io.ByteReader, state *State, dict *DecoderDict, size int64) (d *Decoder, err error) {
	rd, err := newRangeDecoder(br)
	if err != nil {
		return nil, err
	}
	d = &Decoder{
		State: state,
		Dict:  dict,
		rd:    rd,
		size:  size,
		start: dict.Pos(),
	}
	return d, nil
}

// Reopens the decoder with a new byte reader and a new size. Reopen
// resets the Decompressed counter to zero.
func (d *Decoder) Reopen(br io.ByteReader, size int64) error {
	var err error
	if d.rd, err = newRangeDecoder(br); err != nil {
		return err
	}
	d.start = d.Dict.Pos()
	d.size = size
	return nil
}

// decodeLiteral decodes a single literal from the LZMA stream.
func (d *Decoder) decodeLiteral() (op operation, err error) {
	litState := d.State.litState(d.Dict.ByteAt(1), d.Dict.head)
	match := d.Dict.ByteAt(int(d.State.rep[0]) + 1)
	s, err := d.State.litCodec.Decode(d.rd, d.State.state, match, litState)
	if err != nil {
		return nil, err
	}
	return lit{s}, nil
}

// errEOS indicates that an EOS marker has been found.
var errEOS = errors.New("EOS marker found")

// readOp decodes the next operation from the compressed stream. It
// returns the operation. If an explicit end of stream marker is
// identified the eos error is returned.
func (d *Decoder) readOp() (op operation, err error) {
	// Value of the end of stream (EOS) marker
	const eosDist = 1<<32 - 1

	state, state2, posState := d.State.states(d.Dict.head)

	b, err := d.State.isMatch[state2].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// literal
		op, err := d.decodeLiteral()
		if err != nil {
			return nil, err
		}
		d.State.updateStateLiteral()
		return op, nil
	}
	b, err = d.State.isRep[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	if b == 0 {
		// simple match
		d.State.rep[3], d.State.rep[2], d.State.rep[1] =
			d.State.rep[2], d.State.rep[1], d.State.rep[0]

		d.State.updateStateMatch()
		// The length decoder returns the length offset.
		n, err := d.State.lenCodec.Decode(d.rd, posState)
		if err != nil {
			return nil, err
		}
		// The dist decoder returns the distance offset. The actual
		// distance is 1 higher.
		d.State.rep[0], err = d.State.distCodec.Decode(d.rd, n)
		if err != nil {
			return nil, err
		}
		if d.State.rep[0] == eosDist {
			return nil, errEOS
		}
		op = match{n: int(n) + minMatchLen,
			distance: int(d.State.rep[0]) + minDistance}
		return op, nil
	}
	b, err = d.State.isRepG0[state].Decode(d.rd)
	if err != nil {
		return nil, err
	}
	dist := d.State.rep[0]
	if b == 0 {
		// rep match 0
		b, err = d.State.isRepG0Long[state2].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			d.State.updateStateShortRep()
			op = match{n: 1, distance: int(dist) + minDistance}
			return op, nil
		}
	} else {
		b, err = d.State.isRepG1[state].Decode(d.rd)
		if err != nil {
			return nil, err
		}
		if b == 0 {
			dist = d.State.rep[1]
		} else {
			b, err = d.State.isRepG2[state].Decode(d.rd)
			if err != nil {
				return nil, err
			}
			if b == 0 {
				dist = d.State.rep[2]
			} else {
				dist = d.State.rep[3]
				d.State.rep[3] = d.State.rep[2]
			}
			d.State.rep[2] = d.State.rep[1]
		}
		d.State.rep[1] = d.State.rep[0]
		d.State.rep[0] = dist
	}
	n, err := d.State.repLenCodec.Decode(d.rd, posState)
	if err != nil {
		return nil, err
	}
	d.State.updateStateRep()
	op = match{n: int(n) + minMatchLen, distance: int(dist) + minDistance}
	return op, nil
}

// apply takes the operation and transforms the decoder dictionary accordingly.
func (d *Decoder) apply(op operation) error {
	switch x := op.(type) {
	case match:
		return d.Dict.WriteMatch(x.distance, x.n)
	case lit:
		return d.Dict.WriteByte(x.b)
	}
	panic("op is neither a match nor a literal")
}

// decompress fills the dictionary unless no space for new data is
// available. If the end of the LZMA stream has been reached io.EOF will
// be returned.
func (d *Decoder) decompress() error {
	if d.eos {
		return io.EOF
	}
	for d.Dict.Available() >= maxMatchLen {
		op, err := d.readOp()
		switch err {
		case nil:
			break
		case errEOS:
			d.eos = true
			if !d.rd.possiblyAtEnd() {
				return errDataAfterEOS
			}
			if d.size >= 0 && d.size != d.Decompressed() {
				return errSize
			}
			return io.EOF
		case io.EOF:
			d.eos = true
			return io.ErrUnexpectedEOF
		default:
			return err
		}
		if err = d.apply(op); err != nil {
			return err
		}
		if d.size >= 0 && d.Decompressed() >= d.size {
			d.eos = true
			if d.Decompressed() > d.size {
				return errSize
			}
			if !d.rd.possiblyAtEnd() {
				switch _, err = d.readOp(); err {
				case nil:
					return errSize
				case io.EOF:
					return io.ErrUnexpectedEOF
				case errEOS:
					break
				default:
					return err
				}
			}
			return io.EOF
		}
	}
	return nil
}

// Errors that may be returned while decoding data.
var (
	errDataAfterEOS = errors.New("lzma: data after end of stream marker")
	errSize         = errors.New("lzma: wrong uncompressed data size")
)

// Read reads data from the buffer. If no more data is available io.EOF is
// returned.
func (d *Decoder) Read(p []byte) (n int, err error) {
	var k int
	for {
		// Read of decoder dict never returns an error.
		k, err = d.Dict.Read(p[n:])
		if err != nil {
			panic(fmt.Errorf("dictionary read error %s", err))
		}
		if k == 0 && d.eos {
			return n, io.EOF
		}
		n += k
		if n >= len(p) {
			return n, nil
		}
		if err = d.decompress(); err != nil && err != io.EOF {
			return n, err
		}
	}
}

// Decompressed returns the number of bytes decompressed by the decoder.
func (d *Decoder) Decompressed() int64 {
	return d.Dict.Pos() - d.start
}
<|endoftext|>


<commit_before>package knative

import (
	"fmt"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/client/pkg/kn/flags"
	"knative.dev/client/pkg/wait"
	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
	v1 "knative.dev/serving/pkg/apis/serving/v1"

	bosonFunc "github.com/boson-project/func"
	"github.com/boson-project/func/k8s"
)

type Deployer struct {
	// Namespace with which to override that set on the default configuration (such as the ~/.kube/config).
	// If left blank, deployment will commence to the configured namespace.
	Namespace string
	// Verbose logging enablement flag.
	Verbose bool
}

func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
	deployer = &Deployer{}
	namespace, err := GetNamespace(namespaceOverride)
	if err != nil {
		return
	}
	deployer.Namespace = namespace
	return
}

func (d *Deployer) Deploy(f bosonFunc.Function) (err error) {

	// k8s does not support service names with dots. so encode it such that
	// www.my-domain,com -> www-my--domain-com
	serviceName, err := k8s.ToK8sAllowedName(f.Name)
	if err != nil {
		return
	}

	client, err := NewServingClient(d.Namespace)
	if err != nil {
		return
	}

	_, err = client.GetService(serviceName)
	if err != nil {
		if errors.IsNotFound(err) {

			// Let's create a new Service
			if d.Verbose {
				fmt.Printf("Creating Knative Service: %v\n", serviceName)
			}
			service, err := generateNewService(serviceName, f.ImageWithDigest(), f.Runtime, f.EnvVars)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to generate the service: %v", err)
				return err
			}
			err = client.CreateService(service)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to deploy the service: %v", err)
				return err
			}

			if d.Verbose {
				fmt.Println("Waiting for Knative Service to become ready")
			}
			err, _ = client.WaitForService(serviceName, DefaultWaitingTimeout, wait.NoopMessageCallback())
			if err != nil {
				err = fmt.Errorf("knative deployer failed to wait for the service to become ready: %v", err)
				return err
			}

			route, err := client.GetRoute(serviceName)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to get the route: %v", err)
				return err
			}

			fmt.Println("Function deployed at URL: " + route.Status.URL.String())

		} else {
			err = fmt.Errorf("knative deployer failed to get the service: %v", err)
			return err
		}
	} else {
		// Update the existing Service
		err = client.UpdateServiceWithRetry(serviceName, updateService(f.ImageWithDigest(), f.EnvVars), 3)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to update the service: %v", err)
			return err
		}

		route, err := client.GetRoute(serviceName)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to get the route: %v", err)
			return err
		}

		fmt.Println("Function updated at URL: " + route.Status.URL.String())
	}

	return nil
}

func probeFor(url string) *corev1.Probe {
	return &corev1.Probe{
		Handler: corev1.Handler{
			HTTPGet: &corev1.HTTPGetAction{
				Path: url,
			},
		},
	}
}

func generateNewService(name, image, runtime string, envVars map[string]string) (*servingv1.Service, error) {
	containers := []corev1.Container{
		{
			Image: image,
		},
	}

	if runtime != "quarkus" {
		containers[0].LivenessProbe = probeFor("/health/liveness")
		containers[0].ReadinessProbe = probeFor("/health/readiness")
	}

	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"boson.dev/function": "true",
				"boson.dev/runtime":  runtime,
			},
		},
		Spec: v1.ServiceSpec{
			ConfigurationSpec: v1.ConfigurationSpec{
				Template: v1.RevisionTemplateSpec{
					Spec: v1.RevisionSpec{
						PodSpec: corev1.PodSpec{
							Containers: containers,
						},
					},
				},
			},
		},
	}

	return setEnvVars(service, envVars)
}

func updateService(image string, envVars map[string]string) func(service *servingv1.Service) (*servingv1.Service, error) {
	return func(service *servingv1.Service) (*servingv1.Service, error) {
		err := flags.UpdateImage(&service.Spec.Template.Spec.PodSpec, image)
		if err != nil {
			return service, err
		}
		return setEnvVars(service, envVars)
	}
}

func setEnvVars(service *servingv1.Service, envVars map[string]string) (*servingv1.Service, error) {
	builtEnvVarName := "BUILT"
	builtEnvVarValue := time.Now().Format("20060102T150405")

	toUpdate := make(map[string]string, len(envVars)+1)
	toRemove := make([]string, 0)

	for name, value := range envVars {
		if strings.HasSuffix(name, "-") {
			toRemove = append(toRemove, strings.TrimSuffix(name, "-"))
		} else {
			toUpdate[name] = value
		}
	}

	toUpdate[builtEnvVarName] = builtEnvVarValue

	return service, flags.UpdateEnvVars(&service.Spec.Template.Spec.PodSpec, toUpdate, toRemove)
}
<commit_msg>server-side generated Revision name during the update (#274)<commit_after>package knative

import (
	"fmt"
	"strings"
	"time"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"knative.dev/client/pkg/kn/flags"
	"knative.dev/client/pkg/wait"
	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
	v1 "knative.dev/serving/pkg/apis/serving/v1"

	bosonFunc "github.com/boson-project/func"
	"github.com/boson-project/func/k8s"
)

type Deployer struct {
	// Namespace with which to override that set on the default configuration (such as the ~/.kube/config).
	// If left blank, deployment will commence to the configured namespace.
	Namespace string
	// Verbose logging enablement flag.
	Verbose bool
}

func NewDeployer(namespaceOverride string) (deployer *Deployer, err error) {
	deployer = &Deployer{}
	namespace, err := GetNamespace(namespaceOverride)
	if err != nil {
		return
	}
	deployer.Namespace = namespace
	return
}

func (d *Deployer) Deploy(f bosonFunc.Function) (err error) {

	// k8s does not support service names with dots. so encode it such that
	// www.my-domain,com -> www-my--domain-com
	serviceName, err := k8s.ToK8sAllowedName(f.Name)
	if err != nil {
		return
	}

	client, err := NewServingClient(d.Namespace)
	if err != nil {
		return
	}

	_, err = client.GetService(serviceName)
	if err != nil {
		if errors.IsNotFound(err) {

			// Let's create a new Service
			if d.Verbose {
				fmt.Printf("Creating Knative Service: %v\n", serviceName)
			}
			service, err := generateNewService(serviceName, f.ImageWithDigest(), f.Runtime, f.EnvVars)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to generate the service: %v", err)
				return err
			}
			err = client.CreateService(service)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to deploy the service: %v", err)
				return err
			}

			if d.Verbose {
				fmt.Println("Waiting for Knative Service to become ready")
			}
			err, _ = client.WaitForService(serviceName, DefaultWaitingTimeout, wait.NoopMessageCallback())
			if err != nil {
				err = fmt.Errorf("knative deployer failed to wait for the service to become ready: %v", err)
				return err
			}

			route, err := client.GetRoute(serviceName)
			if err != nil {
				err = fmt.Errorf("knative deployer failed to get the route: %v", err)
				return err
			}

			fmt.Println("Function deployed at URL: " + route.Status.URL.String())

		} else {
			err = fmt.Errorf("knative deployer failed to get the service: %v", err)
			return err
		}
	} else {
		// Update the existing Service
		err = client.UpdateServiceWithRetry(serviceName, updateService(f.ImageWithDigest(), f.EnvVars), 3)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to update the service: %v", err)
			return err
		}

		route, err := client.GetRoute(serviceName)
		if err != nil {
			err = fmt.Errorf("knative deployer failed to get the route: %v", err)
			return err
		}

		fmt.Println("Function updated at URL: " + route.Status.URL.String())
	}

	return nil
}

func probeFor(url string) *corev1.Probe {
	return &corev1.Probe{
		Handler: corev1.Handler{
			HTTPGet: &corev1.HTTPGetAction{
				Path: url,
			},
		},
	}
}

func generateNewService(name, image, runtime string, envVars map[string]string) (*servingv1.Service, error) {
	containers := []corev1.Container{
		{
			Image: image,
		},
	}

	if runtime != "quarkus" {
		containers[0].LivenessProbe = probeFor("/health/liveness")
		containers[0].ReadinessProbe = probeFor("/health/readiness")
	}

	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Name: name,
			Labels: map[string]string{
				"boson.dev/function": "true",
				"boson.dev/runtime":  runtime,
			},
		},
		Spec: v1.ServiceSpec{
			ConfigurationSpec: v1.ConfigurationSpec{
				Template: v1.RevisionTemplateSpec{
					Spec: v1.RevisionSpec{
						PodSpec: corev1.PodSpec{
							Containers: containers,
						},
					},
				},
			},
		},
	}

	return setEnvVars(service, envVars)
}

func updateService(image string, envVars map[string]string) func(service *servingv1.Service) (*servingv1.Service, error) {
	return func(service *servingv1.Service) (*servingv1.Service, error) {
		// Removing the name so the k8s server can fill it in with generated name,
		// this prevents conflicts in Revision name when updating the KService from multiple places.
		service.Spec.Template.Name = ""

		err := flags.UpdateImage(&service.Spec.Template.Spec.PodSpec, image)
		if err != nil {
			return service, err
		}
		return setEnvVars(service, envVars)
	}
}

func setEnvVars(service *servingv1.Service, envVars map[string]string) (*servingv1.Service, error) {
	builtEnvVarName := "BUILT"
	builtEnvVarValue := time.Now().Format("20060102T150405")

	toUpdate := make(map[string]string, len(envVars)+1)
	toRemove := make([]string, 0)

	for name, value := range envVars {
		if strings.HasSuffix(name, "-") {
			toRemove = append(toRemove, strings.TrimSuffix(name, "-"))
		} else {
			toUpdate[name] = value
		}
	}

	toUpdate[builtEnvVarName] = builtEnvVarValue

	return service, flags.UpdateEnvVars(&service.Spec.Template.Spec.PodSpec, toUpdate, toRemove)
}
<|endoftext|>


<commit_before>// Copyright 2015-2017 trivago GmbH
//
// 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 core

import (
	//	"sync"
	"testing"
	"time"

	"github.com/trivago/tgo/tlog"
	"github.com/trivago/tgo/ttesting"
)

type mockRouter struct {
	SimpleRouter
}

func (router *mockRouter) Enqueue(msg *Message) error {
	return nil
}

func (router *mockRouter) Start() error {
	return nil
}

func getMockRouter() mockRouter {
	timeout := time.Second
	return mockRouter{
		SimpleRouter: SimpleRouter{
			id:        "testStream",
			filters:   FilterArray{},
			Producers: []Producer{},
			timeout:   timeout,
			streamID:  StreamRegistry.GetStreamID("testStream"),
			Log:       tlog.NewLogScope("testStreamLogScope"),
		},
	}
}

func registerMockRouter(streamName string) {
	mockRouter := getMockRouter()

	mockConf := NewPluginConfig("", "mockRouter")
	mockConf.Override("Stream", streamName)
	mockConf.Override("Modulators", []interface{}{
		"core.mockFormatter",
	})

	mockRouter.Configure(NewPluginConfigReader(&mockConf))
	StreamRegistry.Register(&mockRouter, mockRouter.GetStreamID())
}

func TestRouterConfigureStream(t *testing.T) {
	expect := ttesting.NewExpect(t)
	TypeRegistry.Register(mockFormatter{})

	mockConf := NewPluginConfig("", "core.mockPlugin")
	mockConf.Override("Router", "testBoundStream")
	mockConf.Override("Modulators", []interface{}{
		"core.mockFormatter",
	})
	mockConf.Override("TimeoutMs", 100)

	mockRouter := getMockRouter()
	reader := NewPluginConfigReader(&mockConf)
	err := reader.Configure(&mockRouter)
	expect.Equal(nil, err)
}

func TestStreamRoute(t *testing.T) {
	// TODO
}

func TestRouteOriginalMessage(t *testing.T) {
	expect := ttesting.NewExpect(t)
	mockRouter := getMockRouterMessageHelper("testStream")

	mockConf := NewPluginConfig("", "mockRouter")
	mockConf.Override("Stream", "messageDropStream")

	mockRouter.Configure(NewPluginConfigReader(&mockConf))
	StreamRegistry.Register(&mockRouter, mockRouter.GetStreamID())

	msg := NewMessage(nil, []byte("foo"), mockRouter.GetStreamID())

	err := RouteOriginal(msg, msg.GetRouter())
	expect.NoError(err)

	expect.True(mockRouter.messageEnqued)
	expect.Equal("foo", mockRouter.lastMessageData)

}

func TestRouteOriginal(t *testing.T) {
	expect := ttesting.NewExpect(t)

	// create router mock A
	mockRouterA := getMockRouterMessageHelper("testStreamA")

	mockConfA := NewPluginConfig("mockA", "mockRouterA")
	mockConfA.Override("Stream", "messageDropStreamA")

	mockRouterA.Configure(NewPluginConfigReader(&mockConfA))
	StreamRegistry.Register(&mockRouterA, mockRouterA.GetStreamID())

	// create router mock B
	mockRouterB := getMockRouterMessageHelper("testStreamB")

	mockConfB := NewPluginConfig("mockB", "mockRouterB")
	mockConfB.Override("Stream", "messageDropStreamB")

	mockRouterB.Configure(NewPluginConfigReader(&mockConfB))
	StreamRegistry.Register(&mockRouterB, mockRouterB.GetStreamID())

	// create message and test
	msg := NewMessage(nil, []byte("foo"), mockRouterA.GetStreamID())

	err := RouteOriginal(msg, &mockRouterB)
	expect.NoError(err)

	expect.False(mockRouterA.messageEnqued)
	expect.Equal("", mockRouterA.lastMessageData)
	expect.True(mockRouterB.messageEnqued)
	expect.Equal("foo", mockRouterB.lastMessageData)

}
<commit_msg>Removed remaining direct calls to Configure<commit_after>// Copyright 2015-2017 trivago GmbH
//
// 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 core

import (
	//	"sync"
	"testing"
	"time"

	"github.com/trivago/tgo/tlog"
	"github.com/trivago/tgo/ttesting"
)

type mockRouter struct {
	SimpleRouter
}

func (router *mockRouter) Enqueue(msg *Message) error {
	return nil
}

func (router *mockRouter) Start() error {
	return nil
}

func getMockRouter() mockRouter {
	timeout := time.Second
	return mockRouter{
		SimpleRouter: SimpleRouter{
			id:        "testStream",
			filters:   FilterArray{},
			Producers: []Producer{},
			timeout:   timeout,
			streamID:  StreamRegistry.GetStreamID("testStream"),
			Log:       tlog.NewLogScope("testStreamLogScope"),
		},
	}
}

func registerMockRouter(streamName string) {
	mockRouter := getMockRouter()

	mockConf := NewPluginConfig("", "mockRouter")
	mockConf.Override("Stream", streamName)
	mockConf.Override("Modulators", []interface{}{
		"core.mockFormatter",
	})

	reader := NewPluginConfigReader(&mockConf)
	if err := reader.Configure(&mockRouter); err != nil {
		panic(err)
	}
	StreamRegistry.Register(&mockRouter, mockRouter.GetStreamID())
}

func TestRouterConfigureStream(t *testing.T) {
	expect := ttesting.NewExpect(t)
	TypeRegistry.Register(mockFormatter{})

	mockConf := NewPluginConfig("", "core.mockPlugin")
	mockConf.Override("Router", "testBoundStream")
	mockConf.Override("Modulators", []interface{}{
		"core.mockFormatter",
	})
	mockConf.Override("TimeoutMs", 100)

	mockRouter := getMockRouter()
	reader := NewPluginConfigReader(&mockConf)
	err := reader.Configure(&mockRouter)
	expect.Equal(nil, err)
}

func TestStreamRoute(t *testing.T) {
	// TODO
}

func TestRouteOriginalMessage(t *testing.T) {
	expect := ttesting.NewExpect(t)
	mockRouter := getMockRouterMessageHelper("testStream")

	mockConf := NewPluginConfig("", "mockRouter")
	mockConf.Override("Stream", "messageDropStream")

	reader := NewPluginConfigReader(&mockConf)
	reader.Configure(&mockRouter)
	StreamRegistry.Register(&mockRouter, mockRouter.GetStreamID())

	msg := NewMessage(nil, []byte("foo"), mockRouter.GetStreamID())

	err := RouteOriginal(msg, msg.GetRouter())
	expect.NoError(err)

	expect.True(mockRouter.messageEnqued)
	expect.Equal("foo", mockRouter.lastMessageData)

}

func TestRouteOriginal(t *testing.T) {
	expect := ttesting.NewExpect(t)

	// create router mock A
	mockRouterA := getMockRouterMessageHelper("testStreamA")

	mockConfA := NewPluginConfig("mockA", "mockRouterA")
	mockConfA.Override("Stream", "messageDropStreamA")

	reader := NewPluginConfigReader(&mockConfA)
	reader.Configure(&mockRouterA)
	StreamRegistry.Register(&mockRouterA, mockRouterA.GetStreamID())

	// create router mock B
	mockRouterB := getMockRouterMessageHelper("testStreamB")

	mockConfB := NewPluginConfig("mockB", "mockRouterB")
	mockConfB.Override("Stream", "messageDropStreamB")

	reader = NewPluginConfigReader(&mockConfB)
	reader.Configure(&mockRouterB)
	StreamRegistry.Register(&mockRouterB, mockRouterB.GetStreamID())

	// create message and test
	msg := NewMessage(nil, []byte("foo"), mockRouterA.GetStreamID())

	err := RouteOriginal(msg, &mockRouterB)
	expect.NoError(err)

	expect.False(mockRouterA.messageEnqued)
	expect.Equal("", mockRouterA.lastMessageData)
	expect.True(mockRouterB.messageEnqued)
	expect.Equal("foo", mockRouterB.lastMessageData)

}
<|endoftext|>


<commit_before>// Copyright 2014 Krister Svanlund
//
//    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 matrix

import (
    "bytes"
    "crypto/rand"
    "encoding/base64"
    c "github.com/KoFish/pallium/config"
    "strings"
    "time"
)

type (
    UserID    struct{ DomainSpecificString }
    RoomID    struct{ DomainSpecificString }
    RoomAlias struct{ DomainSpecificString }
    EventID   struct{ DomainSpecificString }
)

var (
    // Default invalid Room ID
    NoRoomID RoomID = RoomID{}
    // Default invalid User ID
    NoUserID UserID = UserID{}
    // Default invalid Event ID
    NoEventID EventID = EventID{}
    // Default invalid Room Alias
    NoRoomAlias RoomAlias = RoomAlias{}
)

func NewUserID(localpart, domain string) (UserID, error) {
    dss, err := makeDSS("@", localpart, domain)
    return UserID{dss}, err
}

func ParseUserID(s string) (UserID, error) {
    dss, err := parseDSS("@", s)
    return UserID{dss}, err
}

func NewRoomID(localpart, domain string) (RoomID, error) {
    dss, err := makeDSS("!", localpart, domain)
    return RoomID{dss}, err
}

func GenerateRoomID() (RoomID, error) {
    rstr := make([]byte, 10)
    if _, err := rand.Read(rstr); err != nil {
        return NoRoomID, err
    }
    localpart := strings.Replace(base64.URLEncoding.EncodeToString(rstr), "=", "", -1)
    return NewRoomID(localpart, c.Hostname)
}

func ParseRoomID(s string) (RoomID, error) {
    dss, err := parseDSS("!", s)
    return RoomID{dss}, err
}

func NewRoomAlias(localpart, domain string) (RoomAlias, error) {
    dss, err := makeDSS("#", localpart, domain)
    return RoomAlias{dss}, err
}

func ParseRoomAlias(s string) (RoomAlias, error) {
    dss, err := parseDSS("#", s)
    return RoomAlias{dss}, err
}

func NewEventID(localpart, domain string) (EventID, error) {
    dss, err := makeDSS("$", localpart, domain)
    return EventID{dss}, err
}

func ParseEventID(s string) (EventID, error) {
    dss, err := parseDSS("$", s)
    return EventID{dss}, err
}

func toBytes(nr int64) []byte {
    var b [8]byte
    for i := 0; i < 8; i++ {
        b[i] = byte((nr >> uint(8*(7-i))) & 0xff)
    }
    return b[:]
}

func GenerateEventID() (ev EventID, err error) {
    idb := bytes.TrimLeft(toBytes(event_id_counter), "\x00")
    event_id_counter += 1
    nowb := bytes.TrimLeft(toBytes(time.Now().Unix()), "\x00")
    rstr := make([]byte, 5)
    if _, err := rand.Read(rstr); err != nil {
        return NoEventID
    }
    evid := bytes.Join([][]byte{rstr, nowb, idb}, []byte{})
    return NewEventID(strings.Replace(base64.URLEncoding.EncodeToString(evid), "=", "", -1), c.Hostname)
}
<commit_msg>Improved token generation<commit_after>// Copyright 2014 Krister Svanlund
//
//    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 matrix

import (
    "bytes"
    "crypto/rand"
    "encoding/base64"
    c "github.com/KoFish/pallium/config"
    "strings"
    "time"
)

type (
    UserID    struct{ DomainSpecificString }
    RoomID    struct{ DomainSpecificString }
    RoomAlias struct{ DomainSpecificString }
    EventID   struct{ DomainSpecificString }
)

var (
    // Default invalid Room ID
    NoRoomID RoomID = RoomID{}
    // Default invalid User ID
    NoUserID UserID = UserID{}
    // Default invalid Event ID
    NoEventID EventID = EventID{}
    // Default invalid Room Alias
    NoRoomAlias RoomAlias = RoomAlias{}
)

func NewUserID(localpart, domain string) (UserID, error) {
    dss, err := makeDSS("@", localpart, domain)
    return UserID{dss}, err
}

func ParseUserID(s string) (UserID, error) {
    dss, err := parseDSS("@", s)
    return UserID{dss}, err
}

func NewRoomID(localpart, domain string) (RoomID, error) {
    dss, err := makeDSS("!", localpart, domain)
    return RoomID{dss}, err
}

func GenerateRoomID() (RoomID, error) {
    rstr := make([]byte, 10)
    if _, err := rand.Read(rstr); err != nil {
        return NoRoomID, err
    }
    localpart := strings.Replace(base64.URLEncoding.EncodeToString(rstr), "=", "", -1)
    return NewRoomID(localpart, c.Hostname)
}

func ParseRoomID(s string) (RoomID, error) {
    dss, err := parseDSS("!", s)
    return RoomID{dss}, err
}

func NewRoomAlias(localpart, domain string) (RoomAlias, error) {
    dss, err := makeDSS("#", localpart, domain)
    return RoomAlias{dss}, err
}

func ParseRoomAlias(s string) (RoomAlias, error) {
    dss, err := parseDSS("#", s)
    return RoomAlias{dss}, err
}

func NewEventID(localpart, domain string) (EventID, error) {
    dss, err := makeDSS("$", localpart, domain)
    return EventID{dss}, err
}

func ParseEventID(s string) (EventID, error) {
    dss, err := parseDSS("$", s)
    return EventID{dss}, err
}

func toBytes(nr int64) []byte {
    var b [8]byte
    for i := 0; i < 8; i++ {
        b[i] = byte((nr >> uint(8*(7-i))) & 0xff)
    }
    return b[:]
}

func GenerateEventID() (ev EventID, err error) {
    idb := bytes.TrimLeft(toBytes(event_id_counter), "\x00")
    event_id_counter += 1
    nowb := bytes.TrimLeft(toBytes(time.Now().Unix()), "\x00")
    rstr := make([]byte, 5)
    if _, err := rand.Read(rstr); err != nil {
        return NoEventID
    }
    evid := bytes.Join([][]byte{rstr, nowb, idb}, []byte{})
    encstr := strings.Replace(base64.URLEncoding.EncodeToString(evid), "=", "", -1)
    encstr = strings.Replace(encstr, "$", ".", -1)
    encstr = strings.Replace(encstr, ":", ".", -1)
    return NewEventID(encstr, c.Hostname)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"reflect"
	"sort"
	"testing"
)

func init() {
	// run against config template
	loadConfig("meowkov.conf.template")
}

func TestParseInput_standard(t *testing.T) {
	test := func(input string, expected []string) {
		words := parseInput(input)
		if !reflect.DeepEqual(words, expected) {
			t.Error("parseInput words " + dump(words) + " do not match expected " + dump(expected))
		}
	}

	// plain message
	input := "1 2 3"
	expectedWords := []string{"1", "2", "3", stop}
	test(input, expectedWords)

	// remove mentions present at the beginning
	input = config.BotName + ": 1 2 3"
	test(input, expectedWords)
	input = config.BotName + ", 1 2 3"
	test(input, expectedWords)

	// remove BotName if used as mention at the beginning
	input = config.BotName + ": look: 2 3"
	expectedWords = []string{"look:", "2", "3", stop}
	test(input, expectedWords)
	input = config.BotName + ", look: 2 3"
	test(input, expectedWords)

	// do not remove BotName if in the middle
	input = "1 " + config.BotName + " 2 3"
	expectedWords = []string{"1", config.BotName, "2", "3", stop}
	test(input, expectedWords)

	// lowercase input with exception of URLs
	input = "PlAy PiAno https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;30"
	expectedWords = []string{"play", "piano", "https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;30", stop}
	test(input, expectedWords)
}

func TestNormalizeWord(t *testing.T) {
	test := func(input string, expected string) {
		normalized := normalizeWord(input)
		if normalized != expected {
			t.Error("normalizeWord result >" + normalized + "< does not match expected >" + expected + "<")
		}
	}

	// strip spaces and lowercase input
	test(" CaSe ", "case")

	// strip spaces but no not lowercase URL
	test("  https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;3 ", "https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;3")

	// remove " from beginning and/or end
	test(" \"foo", "foo")
	test(" foo\" ", "foo")
	test(" \"foo\" ", "foo")
	test(" f\"oo ", "f\"oo")

	// remove ' from beginning and/or end
	test(" 'foo", "foo")
	test(" foo' ", "foo")
	test(" 'foo' ", "foo")
	test(" f'oo ", "f'oo")

	// remove ( and ) from beginning and/or end
	test(" (foo)", "foo")
	test(" (foo ", "foo")
	test(" foo) ", "foo")
	test(" f(oo ", "f(oo")

	// remove [ and ] from beginning and/or end
	test(" [foo]", "foo")
	test(" [foo ", "foo")
	test(" foo] ", "foo")
	test(" f[oo ", "f[oo")

	// remove ? and ! from end only
	test(" foo? ", "foo")
	test(" foo! ", "foo")
	test(" foo!?!?!? ", "foo")
	test(" foo!?bar ", "foo!?bar")
}

func TestGetRedisServer(t *testing.T) {
	config.RedisServer = "foo:1234"
	if getRedisServer() != "foo:1234" {
		t.Error("redis address should be loaded from config")
	}
	os.Setenv("REDIS_PORT_1234_TCP_ADDR", "bar")
	if getRedisServer() != "bar:1234" {
		t.Error("redis address should come from ENV when run in docker")
	}
}

func TestIsEmpty(t *testing.T) {
	problem := !isEmpty("") || !isEmpty(stop)
	if problem {
		t.Error("Empty string should be empty ;-)")
	}
}

func TestIsChainEmpty(t *testing.T) {
	problem := !isChainEmpty([]string{stop}) || !isChainEmpty([]string{}) || !isChainEmpty([]string{""})
	if problem {
		t.Error("Empty slice should be empty ;-)")
	}
}

func TestCalculateChattiness(t *testing.T) {
	privateQuery := false
	chattiness := calculateChattiness("foo bar one two", "nickname", privateQuery)
	if chattiness != config.DefaultChattiness {
		t.Error("calculateChattiness should return DefaultChattiness if bot's nickname is not mentioned")
	}
	chattiness = calculateChattiness("foo bar nickname one two", "nickname", privateQuery)
	if chattiness != always {
		t.Error("calculateChattiness should return 1.0 if nickname is mentioned")
	}
	privateQuery = true
	chattiness = calculateChattiness("foo bar one two", "nickname", privateQuery)
	if chattiness != always {
		t.Error("calculateChattiness should return 1.0 if input is from a private query")
	}

}

func TestInputSource(t *testing.T) {
	rawChannelMsg := ":foo!~bar@unaffiliated/foobar PRIVMSG #test :foo"
	rawPrivateMsg := ":foo!~bar@unaffiliated/foobar PRIVMSG meowkov :foo"
	ownNick := "meowkov"

	source, priv := inputSource(rawChannelMsg, ownNick)
	if source != "#test" || priv {
		t.Error("inputSource should return channel")
	}
	source, priv = inputSource(rawPrivateMsg, ownNick)
	if source != "foo" || !priv {
		t.Error("inputSource should return private query")
	}

}

func TestCreateSeeds(t *testing.T) {
	input := []string{"1", "2", "3", "4", "5", "6"}
	expected := [][]string{
		[]string{"1", "2", "3"},
		[]string{"2", "3", "4"},
		[]string{"3", "4", "5"},
		[]string{"4", "5", "6"},
	}
	output := createSeeds(input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("createSeeds returns incorrect chain groups")
	}
}

func TestContains(t *testing.T) {
	items := []string{"1", "2", "3"}
	test := func(items []string, item string, expected bool) {
		if contains(items, item) != expected {
			t.Error("contains(" + dump(items) + "," + item + ") should return " + fmt.Sprint(expected))
		}
	}
	test(items, "1", true)
	test(items, "2", true)
	test(items, "3", true)
	test(items, "A", false)

}

func TestMutateChain(t *testing.T) {
	input := []string{"1", "2"}
	word := "A"
	expected := []string{"A", "1", "A", "2", "A"}
	output := mutateChain(word, input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("mutateChain should return " + dump(expected))
	}
}

func TestRandomSmiley(t *testing.T) {
	if !contains(config.Smileys, randomSmiley()) {
		t.Error("randomSmiley should return random item from the list in config file")
	}
}

func TestRemoveBlacklistedWords(t *testing.T) {
	blacklistOrig := config.Blacklist
	dontEndOrig := config.DontEndWith

	config.Blacklist = []string{"2"}
	config.DontEndWith = []string{"5", "6"}
	input := []string{"1", "2", "3", "4", "5", "6"}
	expected := []string{"1", "3", "4"}
	output := removeBlacklistedWords(input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("removeBlacklistedWords should return " + dump(expected))
	}

	config.Blacklist = blacklistOrig
	config.DontEndWith = dontEndOrig
}

func TestMedian(t *testing.T) {
	input := []int{1, 2, 3, 4, 5, 6}
	expected := 3
	output := median(input)
	if output != expected {
		t.Error("median should return " + fmt.Sprint(expected) + " but got " + fmt.Sprint(output))
	}
}

func TestNormalizeResponseChains(t *testing.T) {
	input := []string{"1", "1", "22", "333", "4444", "55555", "666666", "666666"}
	expected := []string{"333", "4444", "55555", "666666"}
	output := normalizeResponseChains(input)
	sort.Strings(output)
	if !reflect.DeepEqual(output, expected) {
		t.Error("normalizeResponseChains should return " + dump(expected) + " but got " + dump(output))
	}
}

func TestDump(t *testing.T) {
	input := []string{"1", "2", "3"}
	expected := `["1", "2", "3"]`
	output := dump(input)
	if expected != output {
		t.Error("dump should return " + expected + " but got " + output)
	}
}
<commit_msg>TestProcessInput<commit_after>package main

import (
	"fmt"
	"os"
	"reflect"
	"sort"
	"testing"
)

func init() {
	// run against config template
	loadConfig("meowkov.conf.template")
}

func TestProcessInput(t *testing.T) {
	input := "1 2 3 4 5 6"
	expWords := []string{"1", "2", "3", "4", "5", "6", stop}
	expSeeds := [][]string{
		[]string{"1", "2", "3"},
		[]string{"2", "3", "4"},
		[]string{"3", "4", "5"},
		[]string{"4", "5", "6"},
		[]string{"5", "6", stop},
	}
	words, seeds := processInput(input, false)
	if !reflect.DeepEqual(words, expWords) {
		t.Error("processInput words do not match expected value")
	}
	if !reflect.DeepEqual(seeds, expSeeds) {
		t.Error("processInput seeds do not match expected value")
	}

}

func TestParseInput(t *testing.T) {
	test := func(input string, expected []string) {
		words := parseInput(input)
		if !reflect.DeepEqual(words, expected) {
			t.Error("parseInput words " + dump(words) + " do not match expected " + dump(expected))
		}
	}

	// plain message
	input := "1 2 3"
	expectedWords := []string{"1", "2", "3", stop}
	test(input, expectedWords)

	// remove mentions present at the beginning
	input = config.BotName + ": 1 2 3"
	test(input, expectedWords)
	input = config.BotName + ", 1 2 3"
	test(input, expectedWords)

	// remove BotName if used as mention at the beginning
	input = config.BotName + ": look: 2 3"
	expectedWords = []string{"look:", "2", "3", stop}
	test(input, expectedWords)
	input = config.BotName + ", look: 2 3"
	test(input, expectedWords)

	// do not remove BotName if in the middle
	input = "1 " + config.BotName + " 2 3"
	expectedWords = []string{"1", config.BotName, "2", "3", stop}
	test(input, expectedWords)

	// lowercase input with exception of URLs
	input = "PlAy PiAno https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;30"
	expectedWords = []string{"play", "piano", "https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;30", stop}
	test(input, expectedWords)
}

func TestNormalizeWord(t *testing.T) {
	test := func(input string, expected string) {
		normalized := normalizeWord(input)
		if normalized != expected {
			t.Error("normalizeWord result >" + normalized + "< does not match expected >" + expected + "<")
		}
	}

	// strip spaces and lowercase input
	test(" CaSe ", "case")

	// strip spaces but no not lowercase URL
	test("  https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;3 ", "https://yt.aergia.eu/#v=T0rs3R4E1Sk&t=23;3")

	// remove " from beginning and/or end
	test(" \"foo", "foo")
	test(" foo\" ", "foo")
	test(" \"foo\" ", "foo")
	test(" f\"oo ", "f\"oo")

	// remove ' from beginning and/or end
	test(" 'foo", "foo")
	test(" foo' ", "foo")
	test(" 'foo' ", "foo")
	test(" f'oo ", "f'oo")

	// remove ( and ) from beginning and/or end
	test(" (foo)", "foo")
	test(" (foo ", "foo")
	test(" foo) ", "foo")
	test(" f(oo ", "f(oo")

	// remove [ and ] from beginning and/or end
	test(" [foo]", "foo")
	test(" [foo ", "foo")
	test(" foo] ", "foo")
	test(" f[oo ", "f[oo")

	// remove ? and ! from end only
	test(" foo? ", "foo")
	test(" foo! ", "foo")
	test(" foo!?!?!? ", "foo")
	test(" foo!?bar ", "foo!?bar")
}

func TestGetRedisServer(t *testing.T) {
	config.RedisServer = "foo:1234"
	if getRedisServer() != "foo:1234" {
		t.Error("redis address should be loaded from config")
	}
	os.Setenv("REDIS_PORT_1234_TCP_ADDR", "bar")
	if getRedisServer() != "bar:1234" {
		t.Error("redis address should come from ENV when run in docker")
	}
}

func TestIsEmpty(t *testing.T) {
	problem := !isEmpty("") || !isEmpty(stop)
	if problem {
		t.Error("Empty string should be empty ;-)")
	}
}

func TestIsChainEmpty(t *testing.T) {
	problem := !isChainEmpty([]string{stop}) || !isChainEmpty([]string{}) || !isChainEmpty([]string{""})
	if problem {
		t.Error("Empty slice should be empty ;-)")
	}
}

func TestCalculateChattiness(t *testing.T) {
	privateQuery := false
	chattiness := calculateChattiness("foo bar one two", "nickname", privateQuery)
	if chattiness != config.DefaultChattiness {
		t.Error("calculateChattiness should return DefaultChattiness if bot's nickname is not mentioned")
	}
	chattiness = calculateChattiness("foo bar nickname one two", "nickname", privateQuery)
	if chattiness != always {
		t.Error("calculateChattiness should return 1.0 if nickname is mentioned")
	}
	privateQuery = true
	chattiness = calculateChattiness("foo bar one two", "nickname", privateQuery)
	if chattiness != always {
		t.Error("calculateChattiness should return 1.0 if input is from a private query")
	}

}

func TestInputSource(t *testing.T) {
	rawChannelMsg := ":foo!~bar@unaffiliated/foobar PRIVMSG #test :foo"
	rawPrivateMsg := ":foo!~bar@unaffiliated/foobar PRIVMSG meowkov :foo"
	ownNick := "meowkov"

	source, priv := inputSource(rawChannelMsg, ownNick)
	if source != "#test" || priv {
		t.Error("inputSource should return channel")
	}
	source, priv = inputSource(rawPrivateMsg, ownNick)
	if source != "foo" || !priv {
		t.Error("inputSource should return private query")
	}

}

func TestCreateSeeds(t *testing.T) {
	input := []string{"1", "2", "3", "4", "5", "6"}
	expected := [][]string{
		[]string{"1", "2", "3"},
		[]string{"2", "3", "4"},
		[]string{"3", "4", "5"},
		[]string{"4", "5", "6"},
	}
	output := createSeeds(input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("createSeeds returns incorrect chain groups")
	}
}

func TestContains(t *testing.T) {
	items := []string{"1", "2", "3"}
	test := func(items []string, item string, expected bool) {
		if contains(items, item) != expected {
			t.Error("contains(" + dump(items) + "," + item + ") should return " + fmt.Sprint(expected))
		}
	}
	test(items, "1", true)
	test(items, "2", true)
	test(items, "3", true)
	test(items, "A", false)

}

func TestMutateChain(t *testing.T) {
	input := []string{"1", "2"}
	word := "A"
	expected := []string{"A", "1", "A", "2", "A"}
	output := mutateChain(word, input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("mutateChain should return " + dump(expected))
	}
}

func TestRandomSmiley(t *testing.T) {
	if !contains(config.Smileys, randomSmiley()) {
		t.Error("randomSmiley should return random item from the list in config file")
	}
}

func TestRemoveBlacklistedWords(t *testing.T) {
	blacklistOrig := config.Blacklist
	dontEndOrig := config.DontEndWith

	config.Blacklist = []string{"2"}
	config.DontEndWith = []string{"5", "6"}
	input := []string{"1", "2", "3", "4", "5", "6"}
	expected := []string{"1", "3", "4"}
	output := removeBlacklistedWords(input)
	if !reflect.DeepEqual(output, expected) {
		t.Error("removeBlacklistedWords should return " + dump(expected))
	}

	config.Blacklist = blacklistOrig
	config.DontEndWith = dontEndOrig
}

func TestMedian(t *testing.T) {
	input := []int{1, 2, 3, 4, 5, 6}
	expected := 3
	output := median(input)
	if output != expected {
		t.Error("median should return " + fmt.Sprint(expected) + " but got " + fmt.Sprint(output))
	}
}

func TestNormalizeResponseChains(t *testing.T) {
	input := []string{"1", "1", "22", "333", "4444", "55555", "666666", "666666"}
	expected := []string{"333", "4444", "55555", "666666"}
	output := normalizeResponseChains(input)
	sort.Strings(output)
	if !reflect.DeepEqual(output, expected) {
		t.Error("normalizeResponseChains should return " + dump(expected) + " but got " + dump(output))
	}
}

func TestDump(t *testing.T) {
	input := []string{"1", "2", "3"}
	expected := `["1", "2", "3"]`
	output := dump(input)
	if expected != output {
		t.Error("dump should return " + expected + " but got " + output)
	}
}
<|endoftext|>


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

package lease

import (
	"errors"
	"io"
	"os"
	"sync"
)

// A sentinel error used when a lease has been revoked.
type RevokedError struct {
}

func (re *RevokedError) Error() string {
	return "Lease revoked"
}

// A read-only wrapper around a file that may be revoked, when e.g. there is
// temporary disk space pressure. A read lease may also be upgraded to a write
// lease, if it is still valid.
//
// All methods are safe for concurrent access.
type ReadLease interface {
	io.ReadSeeker
	io.ReaderAt

	// Return the size of the underlying file.
	Size() (size int64, err error)

	// Attempt to upgrade the lease to a read/write lease, returning nil if the
	// lease has been revoked. After upgrading, it is as if the lease has been
	// revoked.
	Upgrade() (rwl ReadWriteLease)

	// Cause the lease to be revoked and any associated resources to be cleaned
	// up, if it has not already been revoked.
	Revoke()
}

type readLease struct {
	mu sync.Mutex

	/////////////////////////
	// Dependencies
	/////////////////////////

	// The leaser that issued this lease.
	leaser *FileLeaser

	// The underlying file, set to nil once revoked.
	//
	// GUARDED_BY(mu)
	file *os.File
}

var _ ReadLease = &readLease{}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Read(p []byte) (n int, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	n, err = rl.file.Read(p)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Seek(
	offset int64,
	whence int) (off int64, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	off, err = rl.file.Seek(offset, whence)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) ReadAt(p []byte, off int64) (n int, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	n, err = rl.file.ReadAt(p, off)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Size() (size int64, err error) {
	err = errors.New("TODO")
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Upgrade() (rwl ReadWriteLease) {
	panic("TODO")
}

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

package lease

import (
	"errors"
	"io"
	"os"
	"sync"
)

// A sentinel error used when a lease has been revoked.
type RevokedError struct {
}

func (re *RevokedError) Error() string {
	return "Lease revoked"
}

// A read-only wrapper around a file that may be revoked, when e.g. there is
// temporary disk space pressure. A read lease may also be upgraded to a write
// lease, if it is still valid.
//
// All methods are safe for concurrent access.
type ReadLease interface {
	io.ReadSeeker
	io.ReaderAt

	// Return the size of the underlying file.
	Size() (size int64, err error)

	// Attempt to upgrade the lease to a read/write lease, returning nil if the
	// lease has been revoked. After upgrading, it is as if the lease has been
	// revoked.
	Upgrade() (rwl ReadWriteLease)

	// Cause the lease to be revoked and any associated resources to be cleaned
	// up, if it has not already been revoked.
	Revoke()
}

type readLease struct {
	mu sync.Mutex

	/////////////////////////
	// Dependencies
	/////////////////////////

	// The leaser that issued this lease.
	leaser *FileLeaser

	// The underlying file, set to nil once revoked.
	//
	// GUARDED_BY(mu)
	file *os.File
}

var _ ReadLease = &readLease{}

func newReadLease(
	leaser *FileLeaser,
	file *os.File) (rl *readLease) {
	rl = &readLease{
		leaser: leaser,
		file:   file,
	}

	return
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Read(p []byte) (n int, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	n, err = rl.file.Read(p)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Seek(
	offset int64,
	whence int) (off int64, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	off, err = rl.file.Seek(offset, whence)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) ReadAt(p []byte, off int64) (n int, err error) {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Have we been revoked?
	if rl.file == nil {
		err = &RevokedError{}
		return
	}

	n, err = rl.file.ReadAt(p, off)
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Size() (size int64, err error) {
	err = errors.New("TODO")
	return
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Upgrade() (rwl ReadWriteLease) {
	panic("TODO")
}

// LOCKS_EXCLUDED(rl.mu)
func (rl *readLease) Revoke() {
	panic("TODO")
}
<|endoftext|>


<commit_before>package handlers

import (
	"github.com/stretchr/testify/assert"
	//	"log"
	"net/http"
	"net/http/httptest"
	"testing"
)

/*func TestSearchMsgSpecsNoResults(t *testing.T) {
	req, err := http.NewRequest("GET", "", nil)
	assert.Nil(t, err)
	w := httptest.NewRecorder()
	handler := http.HandlerFunc(SpecSearch)
	handler.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
}*/

func TestSpecSearchAllResults(t *testing.T) {
	req, err := http.NewRequest("GET", "", nil)
	assert.Nil(t, err)
	w := httptest.NewRecorder()
	handler := http.HandlerFunc(SpecSearch)
	handler.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	//log.Printf("Body: %s", w.Body)
}

func BenchmarkSpecSearchAllResults(b *testing.B) {
	req, err := http.NewRequest("GET", "", nil)
	assert.Nil(b, err)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		w := httptest.NewRecorder()
		handler := http.HandlerFunc(SpecSearch)
		handler.ServeHTTP(w, req)
		assert.Equal(b, http.StatusOK, w.Code)
	}
}

func BenchmarkSpecSearchNoResults(b *testing.B) {
	req, err := http.NewRequest("GET", "?searchterm=sdfusfuspdfsdfjsfjsldfjopsfoa", nil)
	assert.Nil(b, err)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		w := httptest.NewRecorder()
		handler := http.HandlerFunc(SpecSearch)
		handler.ServeHTTP(w, req)
		assert.Equal(b, http.StatusOK, w.Code)
	}
}
<commit_msg>Added test cases<commit_after>package handlers

import (
	"github.com/stretchr/testify/assert"
	//	"log"
	"net/http"
	"net/http/httptest"
	"testing"
)

const (
	searchTermAllResults = ""
	searchTermNoResults  = "ujsdfusdfipsfipsfjöksfösfipsf"
)

func TestSearchMsgSpecsNoResults(t *testing.T) {
	results := searchMsgSpecs(searchTermNoResults)
	assert.Equal(t, 0, len(results))
}

func TestSearchMsgSpecsAllResults(t *testing.T) {
	results := searchMsgSpecs(searchTermAllResults)
	assert.Equal(t, 194, len(results))
}

func TestSearchSegSpecsNoResults(t *testing.T) {
	results := searchSegSpecs(searchTermNoResults)
	assert.Equal(t, 0, len(results))
}

func TestSearchSegSpecsAllResults(t *testing.T) {
	results := searchSegSpecs(searchTermAllResults)
	assert.Equal(t, 156, len(results))
}

func TestSearchCompositeDataElemSpecsNoResults(t *testing.T) {
	results := searchCompositeDataElemSpecs(searchTermNoResults)
	assert.Equal(t, 0, len(results))
}

func TestSearchCompositeDataElemSpecsAllResults(t *testing.T) {
	results := searchCompositeDataElemSpecs(searchTermAllResults)
	assert.Equal(t, 198, len(results))
}

func TestSearchSimpleDataElemSpecsNoResults(t *testing.T) {
	results := searchSimpleDataElemSpecs(searchTermNoResults)
	assert.Equal(t, 0, len(results))
}

func TestSearchSimpleDataElemSpecsAllResults(t *testing.T) {
	results := searchSimpleDataElemSpecs(searchTermAllResults)
	assert.Equal(t, 649, len(results))
}

func TestSpecSearchAllResults(t *testing.T) {
	req, err := http.NewRequest("GET", "", nil)
	assert.Nil(t, err)
	w := httptest.NewRecorder()
	handler := http.HandlerFunc(SpecSearch)
	handler.ServeHTTP(w, req)
	assert.Equal(t, http.StatusOK, w.Code)
	//log.Printf("Body: %s", w.Body)
}

func BenchmarkSpecSearchAllResults(b *testing.B) {
	req, err := http.NewRequest("GET", "", nil)
	assert.Nil(b, err)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		w := httptest.NewRecorder()
		handler := http.HandlerFunc(SpecSearch)
		handler.ServeHTTP(w, req)
		assert.Equal(b, http.StatusOK, w.Code)
	}
}

func BenchmarkSpecSearchNoResults(b *testing.B) {
	req, err := http.NewRequest("GET", "?searchterm="+searchTermNoResults, nil)
	assert.Nil(b, err)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		w := httptest.NewRecorder()
		handler := http.HandlerFunc(SpecSearch)
		handler.ServeHTTP(w, req)
		assert.Equal(b, http.StatusOK, w.Code)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
	"encoding/json"
	"fmt"
	"runtime"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"

	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
)

func NewVirtualNode(superMasterNode *v1.Node) *v1.Node {
	now := metav1.Now()
	n := &v1.Node{
		ObjectMeta: metav1.ObjectMeta{
			Name: superMasterNode.Name,
			Labels: map[string]string{
				constants.LabelVirtualNode: "true",
				v1.LabelOSStable:           runtime.GOOS,
				v1.LabelArchStable:         runtime.GOARCH,
			},
		},
		Spec: v1.NodeSpec{
			Unschedulable: true,
			Taints: []v1.Taint{
				{
					Key:       "node.kubernetes.io/unschedulable",
					Effect:    v1.TaintEffectNoSchedule,
					TimeAdded: &now,
				},
			},
		},
	}

	n.Status.Conditions = nodeConditions()
	n.Status.NodeInfo.OperatingSystem = "Linux"
	n.Status.DaemonEndpoints = v1.NodeDaemonEndpoints{
		KubeletEndpoint: v1.DaemonEndpoint{
			// vn-agent service port. Hard coded for now.
			Port: 10550,
		},
	}

	var addresses []v1.NodeAddress
	for _, a := range superMasterNode.Status.Addresses {
		// notes: drop host name address because tenant apiserver using cluster dns.
		// It could not find the node by hostname through this dns.
		if a.Type != v1.NodeHostName {
			addresses = append(addresses, a)
		}
	}
	n.Status.Addresses = addresses
	n.Status.NodeInfo = superMasterNode.Status.NodeInfo
	n.Status.Capacity = superMasterNode.Status.Capacity
	n.Status.Allocatable = superMasterNode.Status.Allocatable

	return n
}

func nodeConditions() []v1.NodeCondition {
	return []v1.NodeCondition{
		{
			Type:               "Ready",
			Status:             v1.ConditionTrue,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletReady",
			Message:            "kubelet is ready.",
		},
		{
			Type:               "OutOfDisk",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasSufficientDisk",
			Message:            "kubelet has sufficient disk space available",
		},
		{
			Type:               "MemoryPressure",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasSufficientMemory",
			Message:            "kubelet has sufficient memory available",
		},
		{
			Type:               "DiskPressure",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasNoDiskPressure",
			Message:            "kubelet has no disk pressure",
		},
		{
			Type:               "NetworkUnavailable",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "RouteCreated",
			Message:            "RouteController created a route",
		},
	}
}

// patchNodeStatus patches node status.
// Copied from github.com/kubernetes/kubernetes/pkg/util/node
func patchNodeStatus(nodes v1core.NodeInterface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, []byte, error) {
	patchBytes, err := preparePatchBytesforNodeStatus(nodeName, oldNode, newNode)
	if err != nil {
		return nil, nil, err
	}

	updatedNode, err := nodes.Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err)
	}
	return updatedNode, patchBytes, nil
}

func preparePatchBytesforNodeStatus(nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) ([]byte, error) {
	oldData, err := json.Marshal(oldNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for node %q: %v", nodeName, err)
	}

	// Reset spec to make sure only patch for Status or ObjectMeta is generated.
	// Note that we don't reset ObjectMeta here, because:
	// 1. This aligns with Nodes().UpdateStatus().
	// 2. Some component does use this to update node annotations.
	newNode.Spec = oldNode.Spec
	newData, err := json.Marshal(newNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for node %q: %v", nodeName, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for node %q: %v", nodeName, err)
	}
	return patchBytes, nil
}
<commit_msg>attach well known label to vNode<commit_after>/*
Copyright 2019 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package node

import (
	"encoding/json"
	"fmt"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"

	"github.com/kubernetes-sigs/multi-tenancy/incubator/virtualcluster/pkg/syncer/constants"
)

var wellKnownNodeLabelsMap = map[string]struct{}{
	v1.LabelOSStable:   {},
	v1.LabelArchStable: {},
	v1.LabelHostname:   {},
}

func NewVirtualNode(superMasterNode *v1.Node) *v1.Node {
	now := metav1.Now()
	n := &v1.Node{
		ObjectMeta: metav1.ObjectMeta{
			Name: superMasterNode.Name,
		},
		Spec: v1.NodeSpec{
			Unschedulable: true,
			Taints: []v1.Taint{
				{
					Key:       "node.kubernetes.io/unschedulable",
					Effect:    v1.TaintEffectNoSchedule,
					TimeAdded: &now,
				},
			},
		},
	}

	labels := map[string]string{
		constants.LabelVirtualNode: "true",
	}
	for k, v := range superMasterNode.GetLabels() {
		if _, isWellKnown := wellKnownNodeLabelsMap[k]; isWellKnown {
			labels[k] = v
		}
	}
	n.SetLabels(labels)

	n.Status.Conditions = nodeConditions()
	n.Status.NodeInfo.OperatingSystem = "Linux"
	n.Status.DaemonEndpoints = v1.NodeDaemonEndpoints{
		KubeletEndpoint: v1.DaemonEndpoint{
			// vn-agent service port. Hard coded for now.
			Port: 10550,
		},
	}

	var addresses []v1.NodeAddress
	for _, a := range superMasterNode.Status.Addresses {
		// notes: drop host name address because tenant apiserver using cluster dns.
		// It could not find the node by hostname through this dns.
		if a.Type != v1.NodeHostName {
			addresses = append(addresses, a)
		}
	}
	n.Status.Addresses = addresses
	n.Status.NodeInfo = superMasterNode.Status.NodeInfo
	n.Status.Capacity = superMasterNode.Status.Capacity
	n.Status.Allocatable = superMasterNode.Status.Allocatable

	return n
}

func nodeConditions() []v1.NodeCondition {
	return []v1.NodeCondition{
		{
			Type:               "Ready",
			Status:             v1.ConditionTrue,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletReady",
			Message:            "kubelet is ready.",
		},
		{
			Type:               "OutOfDisk",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasSufficientDisk",
			Message:            "kubelet has sufficient disk space available",
		},
		{
			Type:               "MemoryPressure",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasSufficientMemory",
			Message:            "kubelet has sufficient memory available",
		},
		{
			Type:               "DiskPressure",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "KubeletHasNoDiskPressure",
			Message:            "kubelet has no disk pressure",
		},
		{
			Type:               "NetworkUnavailable",
			Status:             v1.ConditionFalse,
			LastHeartbeatTime:  metav1.Now(),
			LastTransitionTime: metav1.Now(),
			Reason:             "RouteCreated",
			Message:            "RouteController created a route",
		},
	}
}

// patchNodeStatus patches node status.
// Copied from github.com/kubernetes/kubernetes/pkg/util/node
func patchNodeStatus(nodes v1core.NodeInterface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, []byte, error) {
	patchBytes, err := preparePatchBytesforNodeStatus(nodeName, oldNode, newNode)
	if err != nil {
		return nil, nil, err
	}

	updatedNode, err := nodes.Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status")
	if err != nil {
		return nil, nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err)
	}
	return updatedNode, patchBytes, nil
}

func preparePatchBytesforNodeStatus(nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) ([]byte, error) {
	oldData, err := json.Marshal(oldNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for node %q: %v", nodeName, err)
	}

	// Reset spec to make sure only patch for Status or ObjectMeta is generated.
	// Note that we don't reset ObjectMeta here, because:
	// 1. This aligns with Nodes().UpdateStatus().
	// 2. Some component does use this to update node annotations.
	newNode.Spec = oldNode.Spec
	newData, err := json.Marshal(newNode)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for node %q: %v", nodeName, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for node %q: %v", nodeName, err)
	}
	return patchBytes, nil
}
<|endoftext|>


<commit_before>package fakebuilder

import (
	"sync"

	"github.com/winston-ci/prole/api/builds"
)

type Builder struct {
	built        []builds.Build
	StartError   error
	StartedBuild *builds.Build
	BuildResult  bool
	BuildError   error

	sync.RWMutex
}

func New() *Builder {
	return &Builder{}
}

func (builder *Builder) Build(build builds.Build) (<-chan builds.Build, <-chan bool, <-chan error) {
	started := make(chan builds.Build, 1)
	finished := make(chan bool, 1)
	errored := make(chan error, 2)

	builder.Lock()
	builder.built = append(builder.built, build)
	builder.Unlock()

	if builder.StartError != nil {
		errored <- builder.StartError
	} else {
		if builder.StartedBuild != nil {
			started <- *builder.StartedBuild
		} else {
			started <- build
		}

		if builder.BuildError != nil {
			errored <- builder.BuildError
		} else {
			finished <- builder.BuildResult
		}
	}

	return started, finished, errored
}

func (builder *Builder) Built() []builds.Build {
	builder.RLock()

	built := make([]builds.Build, len(builder.built))
	copy(built, builder.built)

	builder.RUnlock()

	return built
}
<commit_msg>fix race in scheduler test<commit_after>package fakebuilder

import (
	"sync"

	"github.com/winston-ci/prole/api/builds"
)

type Builder struct {
	built        []builds.Build
	StartError   error
	StartedBuild *builds.Build
	BuildResult  bool
	BuildError   error

	sync.RWMutex
}

func New() *Builder {
	return &Builder{}
}

func (builder *Builder) Build(build builds.Build) (<-chan builds.Build, <-chan bool, <-chan error) {
	started := make(chan builds.Build)
	finished := make(chan bool)
	errored := make(chan error)

	builder.Lock()
	builder.built = append(builder.built, build)
	builder.Unlock()

	go func() {
		if builder.StartError != nil {
			errored <- builder.StartError
		} else {
			if builder.StartedBuild != nil {
				started <- *builder.StartedBuild
			} else {
				started <- build
			}

			if builder.BuildError != nil {
				errored <- builder.BuildError
			} else {
				finished <- builder.BuildResult
			}
		}
	}()

	return started, finished, errored
}

func (builder *Builder) Built() []builds.Build {
	builder.RLock()

	built := make([]builds.Build, len(builder.built))
	copy(built, builder.built)

	builder.RUnlock()

	return built
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
	"log"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
)

// Driver is the interface that talks to Parallels and performs certain
// operations with it. Some of the operations on here may seem overly
// specific, but they were built specifically in mind to handle features
// of the Parallels builder for Packer, and to abstract differences in
// versions out of the builder steps, so sometimes the methods are
// extremely specific.
type Driver interface {
	// Compact a virtual disk image.
	CompactDisk(string) error

	// Adds new CD/DVD drive to the VM and returns name of this device
	DeviceAddCDROM(string, string) (string, error)

	// Get path to the first virtual disk image
	DiskPath(string) (string, error)

	// Import a VM
	Import(string, string, string, bool) error

	// Checks if the VM with the given name is running.
	IsRunning(string) (bool, error)

	// Stop stops a running machine, forcefully.
	Stop(string) error

	// Prlctl executes the given Prlctl command
	Prlctl(...string) error

	// Get the path to the Parallels Tools ISO for the given flavor.
	ToolsISOPath(string) (string, error)

	// Verify checks to make sure that this driver should function
	// properly. If there is any indication the driver can't function,
	// this will return an error.
	Verify() error

	// Version reads the version of Parallels that is installed.
	Version() (string, error)

	// Send scancodes to the vm using the prltype python script.
	SendKeyScanCodes(string, ...string) error

	// Apply default сonfiguration settings to the virtual machine
	SetDefaultConfiguration(string) error

	// Finds the MAC address of the NIC nic0
	MAC(string) (string, error)

	// Finds the IP address of a VM connected that uses DHCP by its MAC address
	IPAddress(string) (string, error)
}

// NewDriver returns a new driver implementation for this version of Parallels
// Desktop, or an error if the driver couldn't be initialized.
func NewDriver() (Driver, error) {
	var drivers map[string]Driver
	var prlctlPath string
	var prlsrvctlPath string
	var supportedVersions []string
	DHCPLeaseFile := "/Library/Preferences/Parallels/parallels_dhcp_leases"

	if runtime.GOOS != "darwin" {
		return nil, fmt.Errorf(
			"Parallels builder works only on \"darwin\" platform!")
	}

	if prlctlPath == "" {
		var err error
		prlctlPath, err = exec.LookPath("prlctl")
		if err != nil {
			return nil, err
		}
	}

	log.Printf("prlctl path: %s", prlctlPath)

	if prlsrvctlPath == "" {
		var err error
		prlsrvctlPath, err = exec.LookPath("prlsrvctl")
		if err != nil {
			return nil, err
		}
	}

	log.Printf("prlsrvctl path: %s", prlsrvctlPath)

	drivers = map[string]Driver{
		"11": &Parallels11Driver{
			Parallels9Driver: Parallels9Driver{
				PrlctlPath:    prlctlPath,
				PrlsrvctlPath: prlsrvctlPath,
				dhcpLeaseFile: DHCPLeaseFile,
			},
		},
		"10": &Parallels10Driver{
			Parallels9Driver: Parallels9Driver{
				PrlctlPath:    prlctlPath,
				PrlsrvctlPath: prlsrvctlPath,
				dhcpLeaseFile: DHCPLeaseFile,
			},
		},
		"9": &Parallels9Driver{
			PrlctlPath:    prlctlPath,
			PrlsrvctlPath: prlsrvctlPath,
			dhcpLeaseFile: DHCPLeaseFile,
		},
	}

	for v, d := range drivers {
		version, _ := d.Version()
		if strings.HasPrefix(version, v) {
			if err := d.Verify(); err != nil {
				return nil, err
			}
			return d, nil
		}
		supportedVersions = append(supportedVersions, v)
	}

	latestDriver := 11
	version, _ := drivers[strconv.Itoa(latestDriver)].Version()
	majVer, _ := strconv.Atoi(strings.SplitN(version, ".", 2)[0])
	if majVer > latestDriver {
		log.Printf("Your version of Parallels Desktop for Mac is %s, Packer will use driver for version %d.", version, latestDriver)
		return drivers[strconv.Itoa(latestDriver)], nil
	}

	return nil, fmt.Errorf(
		"Unable to initialize any driver. Supported Parallels Desktop versions: "+
			"%s\n", strings.Join(supportedVersions, ", "))
}
<commit_msg>spelling: configuration<commit_after>package common

import (
	"fmt"
	"log"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
)

// Driver is the interface that talks to Parallels and performs certain
// operations with it. Some of the operations on here may seem overly
// specific, but they were built specifically in mind to handle features
// of the Parallels builder for Packer, and to abstract differences in
// versions out of the builder steps, so sometimes the methods are
// extremely specific.
type Driver interface {
	// Compact a virtual disk image.
	CompactDisk(string) error

	// Adds new CD/DVD drive to the VM and returns name of this device
	DeviceAddCDROM(string, string) (string, error)

	// Get path to the first virtual disk image
	DiskPath(string) (string, error)

	// Import a VM
	Import(string, string, string, bool) error

	// Checks if the VM with the given name is running.
	IsRunning(string) (bool, error)

	// Stop stops a running machine, forcefully.
	Stop(string) error

	// Prlctl executes the given Prlctl command
	Prlctl(...string) error

	// Get the path to the Parallels Tools ISO for the given flavor.
	ToolsISOPath(string) (string, error)

	// Verify checks to make sure that this driver should function
	// properly. If there is any indication the driver can't function,
	// this will return an error.
	Verify() error

	// Version reads the version of Parallels that is installed.
	Version() (string, error)

	// Send scancodes to the vm using the prltype python script.
	SendKeyScanCodes(string, ...string) error

	// Apply default configuration settings to the virtual machine
	SetDefaultConfiguration(string) error

	// Finds the MAC address of the NIC nic0
	MAC(string) (string, error)

	// Finds the IP address of a VM connected that uses DHCP by its MAC address
	IPAddress(string) (string, error)
}

// NewDriver returns a new driver implementation for this version of Parallels
// Desktop, or an error if the driver couldn't be initialized.
func NewDriver() (Driver, error) {
	var drivers map[string]Driver
	var prlctlPath string
	var prlsrvctlPath string
	var supportedVersions []string
	DHCPLeaseFile := "/Library/Preferences/Parallels/parallels_dhcp_leases"

	if runtime.GOOS != "darwin" {
		return nil, fmt.Errorf(
			"Parallels builder works only on \"darwin\" platform!")
	}

	if prlctlPath == "" {
		var err error
		prlctlPath, err = exec.LookPath("prlctl")
		if err != nil {
			return nil, err
		}
	}

	log.Printf("prlctl path: %s", prlctlPath)

	if prlsrvctlPath == "" {
		var err error
		prlsrvctlPath, err = exec.LookPath("prlsrvctl")
		if err != nil {
			return nil, err
		}
	}

	log.Printf("prlsrvctl path: %s", prlsrvctlPath)

	drivers = map[string]Driver{
		"11": &Parallels11Driver{
			Parallels9Driver: Parallels9Driver{
				PrlctlPath:    prlctlPath,
				PrlsrvctlPath: prlsrvctlPath,
				dhcpLeaseFile: DHCPLeaseFile,
			},
		},
		"10": &Parallels10Driver{
			Parallels9Driver: Parallels9Driver{
				PrlctlPath:    prlctlPath,
				PrlsrvctlPath: prlsrvctlPath,
				dhcpLeaseFile: DHCPLeaseFile,
			},
		},
		"9": &Parallels9Driver{
			PrlctlPath:    prlctlPath,
			PrlsrvctlPath: prlsrvctlPath,
			dhcpLeaseFile: DHCPLeaseFile,
		},
	}

	for v, d := range drivers {
		version, _ := d.Version()
		if strings.HasPrefix(version, v) {
			if err := d.Verify(); err != nil {
				return nil, err
			}
			return d, nil
		}
		supportedVersions = append(supportedVersions, v)
	}

	latestDriver := 11
	version, _ := drivers[strconv.Itoa(latestDriver)].Version()
	majVer, _ := strconv.Atoi(strings.SplitN(version, ".", 2)[0])
	if majVer > latestDriver {
		log.Printf("Your version of Parallels Desktop for Mac is %s, Packer will use driver for version %d.", version, latestDriver)
		return drivers[strconv.Itoa(latestDriver)], nil
	}

	return nil, fmt.Errorf(
		"Unable to initialize any driver. Supported Parallels Desktop versions: "+
			"%s\n", strings.Join(supportedVersions, ", "))
}
<|endoftext|>


<commit_before>package pathutil

import (
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/neovim-go/vim"
)

var pkgPathutil = "pathutil"

// Chdir changes the vim current working directory.
// The returned function restores working directory to `getcwd()` result path
// and unlocks the mutex.
func Chdir(v *vim.Vim, dir string) func() {
	var (
		m   sync.Mutex
		cwd interface{}
	)
	m.Lock()
	if err := v.Eval("getcwd()", &cwd); err != nil {
		return nil
	}
	v.ChangeDirectory(dir)
	return func() {
		v.ChangeDirectory(cwd.(string))
		m.Unlock()
	}
}

func RelPath(f, cwd string) string {
	if filepath.HasPrefix(f, cwd) {
		return strings.Replace(f, cwd+string(filepath.Separator), "", 1)
	}
	rel, _ := filepath.Rel(cwd, f)
	return rel
}

func Expand(p string) string {
	switch {
	case strings.Index(p, "$GOROOT") != 1:
		return strings.Replace(p, "$GOROOT", runtime.GOROOT(), 1)
	}

	return p // Not hit
}
<commit_msg>pathutil: Add IsDir and IsExist wrapper function<commit_after>package pathutil

import (
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"

	"github.com/neovim-go/vim"
)

var pkgPathutil = "pathutil"

// Chdir changes the vim current working directory.
// The returned function restores working directory to `getcwd()` result path
// and unlocks the mutex.
func Chdir(v *vim.Vim, dir string) func() {
	var (
		m   sync.Mutex
		cwd interface{}
	)
	m.Lock()
	if err := v.Eval("getcwd()", &cwd); err != nil {
		return nil
	}
	v.ChangeDirectory(dir)
	return func() {
		v.ChangeDirectory(cwd.(string))
		m.Unlock()
	}
}

func RelPath(f, cwd string) string {
	if filepath.HasPrefix(f, cwd) {
		return strings.Replace(f, cwd+string(filepath.Separator), "", 1)
	}
	rel, _ := filepath.Rel(cwd, f)
	return rel
}

func Expand(p string) string {
	switch {
	case strings.Index(p, "$GOROOT") != 1:
		return strings.Replace(p, "$GOROOT", runtime.GOROOT(), 1)
	}

	return p // Not hit
}

func IsDir(filename string) bool {
	fi, err := os.Stat(filename)
	return err == nil && fi.IsDir()
}

func IsExist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil
}
<|endoftext|>


<commit_before>package model

type DocStorer interface {
	GetDoc(id int) (*Document, error)
	CreateDoc(doc *Document) error
	UpdateDoc(doc *Document) error
	DeleteDoc(id int) (int, error)
}

func NewDocument(id int) *Document {
	return &Document{ID: id, Pairs: make(map[string]string)}
}

type Document struct {
	ID    int               `db:"id" json:"id"`
	Pairs map[string]string `db:"pairs" json:"pairs"`
}

func (d *Document) SyncKeys(t []string, additive bool) {
	if d.Pairs == nil || !additive {
		d.Pairs = make(map[string]string)
	}

	for _, v := range t {
		d.Pairs[v] = d.Pairs[v]
	}
}

type Project struct {
	ID    int            `db:"id" json:"id"`
	Keys  []string       `db:"keys" json:"keys"`
	Langs map[string]int `db:"langs" json:"langs"`
}
<commit_msg>Add SyncKeys doc<commit_after>package model

type DocStorer interface {
	GetDoc(id int) (*Document, error)
	CreateDoc(doc *Document) error
	UpdateDoc(doc *Document) error
	DeleteDoc(id int) (int, error)
}

func NewDocument(id int) *Document {
	return &Document{ID: id, Pairs: make(map[string]string)}
}

type Document struct {
	ID    int               `db:"id" json:"id"`
	Pairs map[string]string `db:"pairs" json:"pairs"`
}

// SyncKeys will add new keys from string slice t to document pairs.
// If additive is set to false, previous key/value pairs will be destroyed,
// and if set to true they will be kept.
func (d *Document) SyncKeys(t []string, additive bool) {
	if d.Pairs == nil || !additive {
		d.Pairs = make(map[string]string)
	}

	// Assign each key, if it's already there it will simply reassign to there
	// previous value, otherwise an empty string will be set
	for _, v := range t {
		d.Pairs[v] = d.Pairs[v]
	}
}

type Project struct {
	ID    int            `db:"id" json:"id"`
	Keys  []string       `db:"keys" json:"keys"`
	Langs map[string]int `db:"langs" json:"langs"`
}
<|endoftext|>