<commit_before>package check

import (
	"fmt"
	"plaid/parser"
	"sort"
)

)

// Check takes an existing abstract syntax tree and performs type checks and
// other correctness checks. It returns a list of any errors that were
// discovered inside the AST
func Check(prog parser.Program) *Scope {
	global := makeScope(nil)
	checkProgram(global, prog)
	return global
}

// Scope tracks the symbol table and other data used during the check
type Scope struct {
	parent    *Scope
	variables map[string]Type
	Errs      []error
}

func (s *Scope) hasParent() bool {
	return (s.parent != nil)
}

func (s *Scope) registerVariable(name string, typ Type) {
	s.variables[name] = typ
}

func (s *Scope) hasVariable(name string) bool {
	_, exists := s.variables[name]
	return exists
}

func (s *Scope) getVariable(name string) Type {
	return s.variables[name]
}

func (s *Scope) addError(err error) {
	if s.hasParent() {
		s.parent.addError(err)
	} else {
		s.Errs = append(s.Errs, err)
	}
}

func (s *Scope) String() string {
	names := []string{}
	for name := range s.variables {
		names = append(names, name)
	}
	sort.Strings(names)

	out := "+----------+--------------+\n"
	out += "| Var      | Type         |\n"
	out += "| -------- | ------------ |\n"
	for _, name := range names {
		out += fmt.Sprintf("| %-8s | %-12s |\n", name, s.variables[name])
	}
	out += "+----------+--------------+\n"
	return out
}

func makeScope(parent *Scope) *Scope {
	scope := &Scope{
		parent,
		make(map[string]Type),
		[]error{},
	}

	return scope
}

func checkProgram(scope *Scope, prog parser.Program) {
	for _, stmt := range prog.Stmts {
		switch stmt := stmt.(type) {
		default:
			panic("unknown statement type")
		}
	}
}

}
<commit_msg>remove panic<commit_after>package check

import (
	"fmt"
	"plaid/parser"
	"sort"
)

)

// Check takes an existing abstract syntax tree and performs type checks and
// other correctness checks. It returns a list of any errors that were
// discovered inside the AST
func Check(prog parser.Program) *Scope {
	global := makeScope(nil)
	checkProgram(global, prog)
	return global
}

// Scope tracks the symbol table and other data used during the check
type Scope struct {
	parent    *Scope
	variables map[string]Type
	Errs      []error
}

func (s *Scope) hasParent() bool {
	return (s.parent != nil)
}

func (s *Scope) registerVariable(name string, typ Type) {
	s.variables[name] = typ
}

func (s *Scope) hasVariable(name string) bool {
	_, exists := s.variables[name]
	return exists
}

func (s *Scope) getVariable(name string) Type {
	return s.variables[name]
}

func (s *Scope) addError(err error) {
	if s.hasParent() {
		s.parent.addError(err)
	} else {
		s.Errs = append(s.Errs, err)
	}
}

func (s *Scope) String() string {
	names := []string{}
	for name := range s.variables {
		names = append(names, name)
	}
	sort.Strings(names)

	out := "+----------+--------------+\n"
	out += "| Var      | Type         |\n"
	out += "| -------- | ------------ |\n"
	for _, name := range names {
		out += fmt.Sprintf("| %-8s | %-12s |\n", name, s.variables[name])
	}
	out += "+----------+--------------+\n"
	return out
}

func makeScope(parent *Scope) *Scope {
	scope := &Scope{
		parent,
		make(map[string]Type),
		[]error{},
	}

	return scope
}

func checkProgram(scope *Scope, prog parser.Program) {
	for _, stmt := range prog.Stmts {
		switch stmt := stmt.(type) {
		}
	}
}

}
<|endoftext|>


<commit_before>package pilosa

import (
	"fmt"
	"io"
	"log"
	"os"

	"golang.org/x/sync/errgroup"

	"github.com/gogo/protobuf/proto"
	"github.com/hashicorp/memberlist"
	"github.com/pilosa/pilosa/internal"
)

// GossipNodeSet represents a gossip implementation of NodeSet using memberlist
// GossipNodeSet also represents a gossip implementation of pilosa.Broadcaster
// GossipNodeSet also represents an implementation of memberlist.Delegate
type GossipNodeSet struct {
	memberlist *memberlist.Memberlist
	handler    BroadcastHandler

	broadcasts *memberlist.TransmitLimitedQueue

	server *Server

	config *GossipConfig

	// The writer for any logging.
	LogOutput io.Writer
}

func (g *GossipNodeSet) Nodes() []*Node {
	a := make([]*Node, 0, g.memberlist.NumMembers())
	for _, n := range g.memberlist.Members() {
		a = append(a, &Node{Host: n.Name})
	}
	return a
}

func (g *GossipNodeSet) Start(h BroadcastHandler) error {
	g.handler = h
	return nil
}

func (g *GossipNodeSet) Open() error {
	if g.handler == nil {
		return fmt.Errorf("opening GossipNodeSet: you must call Start(pilosa.BroadcastHandler) before calling Open()")
	}
	ml, err := memberlist.Create(g.config.memberlistConfig)
	if err != nil {
		return err
	}
	g.memberlist = ml

	// attach to gossip seed node
	nodes := []*Node{&Node{Host: g.config.gossipSeed}} //TODO: support a list of seeds
	_, err = g.memberlist.Join(Nodes(nodes).Hosts())
	if err != nil {
		return err
	}
	g.broadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			return ml.NumMembers()
		},
		RetransmitMult: 3,
	}
	return nil
}

// logger returns a logger for the GossipNodeSet.
func (g *GossipNodeSet) logger() *log.Logger {
	return log.New(g.LogOutput, "", log.LstdFlags)
}

////////////////////////////////////////////////////////////////

type GossipConfig struct {
	gossipSeed       string
	memberlistConfig *memberlist.Config
}

// NewGossipNodeSet returns a new instance of GossipNodeSet.
func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, s *Server) *GossipNodeSet {
	g := &GossipNodeSet{
		LogOutput: os.Stderr,
	}

	//TODO: pull memberlist config from pilosa.cfg file
	g.config = &GossipConfig{
		memberlistConfig: memberlist.DefaultLocalConfig(),
		gossipSeed:       gossipSeed,
	}
	g.config.memberlistConfig.Name = name
	g.config.memberlistConfig.BindAddr = gossipHost
	g.config.memberlistConfig.BindPort = gossipPort
	g.config.memberlistConfig.AdvertiseAddr = gossipHost
	g.config.memberlistConfig.AdvertisePort = gossipPort
	g.config.memberlistConfig.Delegate = g

	g.server = s

	return g
}

// SendSync implementation of the Broadcaster interface
func (g *GossipNodeSet) SendSync(pb proto.Message) error {
	msg, err := MarshalMessage(pb)
	if err != nil {
		return err
	}

	mlist := g.server.Cluster.NodeSet.(*GossipNodeSet).memberlist

	// Direct sends the message directly to every node.
	// An error from any node raises an error on the entire operation.
	//
	// Gossip uses the gossip protocol to eventually deliver the message
	// to every node.
	var eg errgroup.Group
	for _, n := range mlist.Members() {
		// Don't send the message to the local node.
		if n == mlist.LocalNode() {
			continue
		}
		node := n
		eg.Go(func() error {
			return mlist.SendToTCP(node, msg)
		})
	}
	return eg.Wait()
}

// SendAsync implementation of the Broadcaster interface
func (g *GossipNodeSet) SendAsync(pb proto.Message) error {
	msg, err := MarshalMessage(pb)
	if err != nil {
		return err
	}

	b := &broadcast{
		msg:    msg,
		notify: nil,
	}
	g.broadcasts.QueueBroadcast(b)
	return nil
}

func (g *GossipNodeSet) Receive(pb proto.Message) error {
	if err := g.handler.ReceiveMessage(pb); err != nil {
		return err
	}
	return nil
}

// implementation of the memberlist.Delegate interface
func (g *GossipNodeSet) NodeMeta(limit int) []byte {
	return []byte{}
}

func (g *GossipNodeSet) NotifyMsg(b []byte) {
	m, err := UnmarshalMessage(b)
	if err != nil {
		g.logger().Printf("unmarshal message error: %s", err)
		return
	}
	if err := g.Receive(m); err != nil {
		g.logger().Printf("receive message error: %s", err)
		return
	}
}

func (g *GossipNodeSet) GetBroadcasts(overhead, limit int) [][]byte {
	return g.broadcasts.GetBroadcasts(overhead, limit)
}

func (g *GossipNodeSet) LocalState(join bool) []byte {
	pb, err := g.server.LocalState()
	if err != nil {
		g.logger().Printf("error getting local state, err=%s", err)
		return []byte{}
	}

	// Marshal nodestate data to bytes.
	buf, err := proto.Marshal(pb)
	if err != nil {
		g.logger().Printf("error marshalling nodestate data, err=%s", err)
		return []byte{}
	}
	return buf
}

func (g *GossipNodeSet) MergeRemoteState(buf []byte, join bool) {
	// Unmarshal nodestate data.
	var pb internal.NodeState
	if err := proto.Unmarshal(buf, &pb); err != nil {
		g.logger().Printf("error unmarshalling nodestate data, err=%s", err)
		return
	}
	err := g.server.HandleRemoteState(&pb)
	if err != nil {
		g.logger().Printf("merge state error: %s", err)
	}
}

// broadcast represents an implementation of memberlist.Broadcast
type broadcast struct {
	msg    []byte
	notify chan<- struct{}
}

func (b *broadcast) Invalidates(other memberlist.Broadcast) bool {
	return false
}

func (b *broadcast) Message() []byte {
	return b.msg
}

func (b *broadcast) Finished() {
	if b.notify != nil {
		close(b.notify)
	}
}
<commit_msg>add stateHandler interface to gossip<commit_after>package pilosa

import (
	"fmt"
	"io"
	"log"
	"os"

	"golang.org/x/sync/errgroup"

	"github.com/gogo/protobuf/proto"
	"github.com/hashicorp/memberlist"
	"github.com/pilosa/pilosa/internal"
)

// StateHandler specifies two methods which an object must implement to share
// state in the cluster. These are used by the GossipNodeSet to implement the
// LocalState and MergeRemoteState methods of memberlist.Delegate
type StateHandler interface {
	LocalState() (proto.Message, error)
	HandleRemoteState(proto.Message) error
}

// GossipNodeSet represents a gossip implementation of NodeSet using memberlist
// GossipNodeSet also represents a gossip implementation of pilosa.Broadcaster
// GossipNodeSet also represents an implementation of memberlist.Delegate
type GossipNodeSet struct {
	memberlist *memberlist.Memberlist
	handler    BroadcastHandler

	broadcasts *memberlist.TransmitLimitedQueue

	stateHandler StateHandler
	config       *GossipConfig

	// The writer for any logging.
	LogOutput io.Writer
}

func (g *GossipNodeSet) Nodes() []*Node {
	a := make([]*Node, 0, g.memberlist.NumMembers())
	for _, n := range g.memberlist.Members() {
		a = append(a, &Node{Host: n.Name})
	}
	return a
}

func (g *GossipNodeSet) Start(h BroadcastHandler) error {
	g.handler = h
	return nil
}

func (g *GossipNodeSet) Open() error {
	if g.handler == nil {
		return fmt.Errorf("opening GossipNodeSet: you must call Start(pilosa.BroadcastHandler) before calling Open()")
	}
	ml, err := memberlist.Create(g.config.memberlistConfig)
	if err != nil {
		return err
	}
	g.memberlist = ml

	// attach to gossip seed node
	nodes := []*Node{&Node{Host: g.config.gossipSeed}} //TODO: support a list of seeds
	_, err = g.memberlist.Join(Nodes(nodes).Hosts())
	if err != nil {
		return err
	}
	g.broadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			return ml.NumMembers()
		},
		RetransmitMult: 3,
	}
	return nil
}

// logger returns a logger for the GossipNodeSet.
func (g *GossipNodeSet) logger() *log.Logger {
	return log.New(g.LogOutput, "", log.LstdFlags)
}

////////////////////////////////////////////////////////////////

type GossipConfig struct {
	gossipSeed       string
	memberlistConfig *memberlist.Config
}

// NewGossipNodeSet returns a new instance of GossipNodeSet.
func NewGossipNodeSet(name string, gossipHost string, gossipPort int, gossipSeed string, sh StateHandler) *GossipNodeSet {
	g := &GossipNodeSet{
		LogOutput: os.Stderr,
	}

	//TODO: pull memberlist config from pilosa.cfg file
	g.config = &GossipConfig{
		memberlistConfig: memberlist.DefaultLocalConfig(),
		gossipSeed:       gossipSeed,
	}
	g.config.memberlistConfig.Name = name
	g.config.memberlistConfig.BindAddr = gossipHost
	g.config.memberlistConfig.BindPort = gossipPort
	g.config.memberlistConfig.AdvertiseAddr = gossipHost
	g.config.memberlistConfig.AdvertisePort = gossipPort
	g.config.memberlistConfig.Delegate = g

	g.stateHandler = sh

	return g
}

// SendSync implementation of the Broadcaster interface
func (g *GossipNodeSet) SendSync(pb proto.Message) error {
	msg, err := MarshalMessage(pb)
	if err != nil {
		return err
	}

	mlist := g.memberlist

	// Direct sends the message directly to every node.
	// An error from any node raises an error on the entire operation.
	//
	// Gossip uses the gossip protocol to eventually deliver the message
	// to every node.
	var eg errgroup.Group
	for _, n := range mlist.Members() {
		// Don't send the message to the local node.
		if n == mlist.LocalNode() {
			continue
		}
		node := n
		eg.Go(func() error {
			return mlist.SendToTCP(node, msg)
		})
	}
	return eg.Wait()
}

// SendAsync implementation of the Broadcaster interface
func (g *GossipNodeSet) SendAsync(pb proto.Message) error {
	msg, err := MarshalMessage(pb)
	if err != nil {
		return err
	}

	b := &broadcast{
		msg:    msg,
		notify: nil,
	}
	g.broadcasts.QueueBroadcast(b)
	return nil
}

func (g *GossipNodeSet) Receive(pb proto.Message) error {
	if err := g.handler.ReceiveMessage(pb); err != nil {
		return err
	}
	return nil
}

// implementation of the memberlist.Delegate interface
func (g *GossipNodeSet) NodeMeta(limit int) []byte {
	return []byte{}
}

func (g *GossipNodeSet) NotifyMsg(b []byte) {
	m, err := UnmarshalMessage(b)
	if err != nil {
		g.logger().Printf("unmarshal message error: %s", err)
		return
	}
	if err := g.Receive(m); err != nil {
		g.logger().Printf("receive message error: %s", err)
		return
	}
}

func (g *GossipNodeSet) GetBroadcasts(overhead, limit int) [][]byte {
	return g.broadcasts.GetBroadcasts(overhead, limit)
}

func (g *GossipNodeSet) LocalState(join bool) []byte {
	pb, err := g.stateHandler.LocalState()
	if err != nil {
		g.logger().Printf("error getting local state, err=%s", err)
		return []byte{}
	}

	// Marshal nodestate data to bytes.
	buf, err := proto.Marshal(pb)
	if err != nil {
		g.logger().Printf("error marshalling nodestate data, err=%s", err)
		return []byte{}
	}
	return buf
}

func (g *GossipNodeSet) MergeRemoteState(buf []byte, join bool) {
	// Unmarshal nodestate data.
	var pb internal.NodeState
	if err := proto.Unmarshal(buf, &pb); err != nil {
		g.logger().Printf("error unmarshalling nodestate data, err=%s", err)
		return
	}
	err := g.stateHandler.HandleRemoteState(&pb)
	if err != nil {
		g.logger().Printf("merge state error: %s", err)
	}
}

// broadcast represents an implementation of memberlist.Broadcast
type broadcast struct {
	msg    []byte
	notify chan<- struct{}
}

func (b *broadcast) Invalidates(other memberlist.Broadcast) bool {
	return false
}

func (b *broadcast) Message() []byte {
	return b.msg
}

func (b *broadcast) Finished() {
	if b.notify != nil {
		close(b.notify)
	}
}
<|endoftext|>


<commit_before>package os

import (
	"errors"
	"io/ioutil"
	"strings"
	"sync"
)

var (
	// osReleaseFile is the name of the file that is read in order to determine
	// the linux type release version.
	osReleaseFile = "/etc/os-release"
	osOnce        sync.Once
	os            OSType // filled in by the first call to hostOS
)

func hostOS() OSType {
	osOnce.Do(func() {
		var err error
		os, err = updateOS(osReleaseFile)
		if err != nil {
			panic("unable to read " + osReleaseFile + ": " + err.Error())
		}
	})
	return os
}

var defaultVersionIDs = map[string]string{
	"arch": "rolling",
}

func updateOS(f string) (OSType, error) {
	values, err := ReadOSRelease(f)
	if err != nil {
		return Unknown, err
	}
	switch values["ID"] {
	case strings.ToLower(Ubuntu.String()):
		return Ubuntu, nil
	case strings.ToLower(Arch.String()):
		return Arch, nil
	case strings.ToLower(CentOS.String()):
		return CentOS, nil
	case strings.ToLower(Debian.String()):
		return Debian, nil
	default:
		return Unknown, nil
	}
}

// ReadOSRelease parses the information in the os-release file.
//
// See http://www.freedesktop.org/software/systemd/man/os-release.html.
func ReadOSRelease(f string) (map[string]string, error) {
	contents, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, err
	}
	values := make(map[string]string)
	releaseDetails := strings.Split(string(contents), "\n")
	for _, val := range releaseDetails {
		c := strings.SplitN(val, "=", 2)
		if len(c) != 2 {
			continue
		}
		values[c[0]] = strings.Trim(c[1], "\t '\"")
	}
	id, ok := values["ID"]
	if !ok {
		return nil, errors.New("OS release file is missing ID")
	}
	if _, ok := values["VERSION_ID"]; !ok {
		values["VERSION_ID"], ok = defaultVersionIDs[id]
		if !ok {
			return nil, errors.New("OS release file is missing VERSION_ID")
		}
	}
	return values, nil
}
<commit_msg>commit (#57)<commit_after>package os

import (
	"errors"
	"io/ioutil"
	"strings"
	"sync"
)

var (
	// osReleaseFile is the name of the file that is read in order to determine
	// the linux type release version.
	osReleaseFile = "/etc/os-release"
	osFile				= "/etc/redhat-release"
	osOnce        sync.Once
	os            OSType // filled in by the first call to hostOS
)

func hostOS() OSType {
	osOnce.Do(func() {
		var err error
		os, err = updateOS(osReleaseFile)
		if err != nil {
			panic("unable to read " + osReleaseFile + ": " + err.Error())
		}
	})
	return os
}

var defaultVersionIDs = map[string]string{
	"arch": "rolling",
}

func updateOS(f string) (OSType, error) {
values := make(map[string]string)
if _, err := ioutil.ReadFile(f); err == nil {
	values, err = ReadOSRelease(f)
	if err != nil {
		return Unknown, err
	}
}else{
	values, err = ReadRelease(osFile)
	if err != nil{
		return Unknown, err
	}
}
	switch values["ID"] {
	case strings.ToLower(Ubuntu.String()):
		return Ubuntu, nil
	case strings.ToLower(Arch.String()):
		return Arch, nil
	case strings.ToLower(CentOS.String()):
		return CentOS, nil
	case strings.ToLower(Debian.String()):
		return Debian, nil
	default:
		return Unknown, nil
	}
}

// ReadOSRelease parses the information in the os-release file.
//
// See http://www.freedesktop.org/software/systemd/man/os-release.html.
func ReadOSRelease(f string) (map[string]string, error) {
	contents, err := ioutil.ReadFile(f)
	if err != nil {
		return nil, err
	}
	values := make(map[string]string)
	releaseDetails := strings.Split(string(contents), "\n")
	for _, val := range releaseDetails {
		c := strings.SplitN(val, "=", 2)
		if len(c) != 2 {
			continue
		}
		values[c[0]] = strings.Trim(c[1], "\t '\"")
	}
	id, ok := values["ID"]
	if !ok {
		return nil, errors.New("OS release file is missing ID")
	}
	if _, ok := values["VERSION_ID"]; !ok {
		values["VERSION_ID"], ok = defaultVersionIDs[id]
		if !ok {
			return nil, errors.New("OS release file is missing VERSION_ID")
		}
	}
	return values, nil
}

// ReadRelease parses the information in the redhat-release file.

func ReadRelease (f string) (map[string]string, error){
	stream, err := ioutil.ReadFile(osFile);
	if err != nil {
		return nil, err
	}
	values := make(map[string]string)
	releaseDetail := strings.Split(string(stream)," ")
	values["ID"] = releaseDetail[0]
	values["VERSION_ID"] = releaseDetail[2]
	id, ok := values["ID"]
	if !ok {
		return nil, errors.New("OS release file is missing ID")
	}
	if _, ok := values["VERSION_ID"]; !ok {
		values["VERSION_ID"], ok = defaultVersionIDs[id]
		if !ok {
			return nil, errors.New("OS release file is missing VERSION_ID")
		}
	}
	return values, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2014 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 main

import (
	"flag"
	"io/ioutil"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
)

var (
	authConfig = flag.String("auth_config", os.Getenv("HOME")+"/.kubernetes_auth", "Path to the auth info file.")
	host       = flag.String("host", "", "The host to connect to")
)

func waitForPodRunning(c *client.Client, id string) {
	for {
		time.Sleep(5 * time.Second)
		pod, err := c.Pods(api.NamespaceDefault).Get(id)
		if err != nil {
			glog.Warningf("Get pod failed: %v", err)
			continue
		}
		if pod.CurrentState.Status == api.PodRunning {
			break
		}
		glog.Infof("Waiting for pod status to be running (%s)", pod.CurrentState.Status)
	}
}

func loadObjectOrDie(filePath string) interface{} {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		glog.Fatalf("Failed to read pod: %v", err)
	}
	obj, err := latest.Codec.Decode(data)
	if err != nil {
		glog.Fatalf("Failed to decode pod: %v", err)
	}
	return obj
}

func loadPodOrDie(filePath string) *api.Pod {
	obj := loadObjectOrDie(filePath)
	pod, ok := obj.(*api.Pod)
	if !ok {
		glog.Fatalf("Failed to load pod: %v", obj)
	}
	return pod
}

func loadClientOrDie() *client.Client {
	config := client.Config{
		Host: *host,
	}
	auth, err := clientauth.LoadFromFile(*authConfig)
	if err != nil {
		glog.Fatalf("Error loading auth: %v", err)
	}
	config, err = auth.MergeWithConfig(config)
	if err != nil {
		glog.Fatalf("Error creating client")
	}
	c, err := client.New(&config)
	if err != nil {
		glog.Fatalf("Error creating client")
	}
	return c
}

func TestKubernetesROService(c *client.Client) bool {
	svc := api.ServiceList{}
	err := c.Get().
		Namespace("default").
		AbsPath("/api/v1beta1/proxy/services/kubernetes-ro/api/v1beta1/services").
		Do().
		Into(&svc)
	if err != nil {
		glog.Errorf("unexpected error listing services using ro service: %v", err)
		return false
	}
	var foundRW, foundRO bool
	for i := range svc.Items {
		if svc.Items[i].Name == "kubernetes" {
			foundRW = true
		}
		if svc.Items[i].Name == "kubernetes-ro" {
			foundRO = true
		}
	}
	if !foundRW {
		glog.Error("no RW service found")
	}
	if !foundRO {
		glog.Error("no RO service found")
	}
	if !foundRW || !foundRO {
		return false
	}
	return true
}

func TestPodUpdate(c *client.Client) bool {
	podClient := c.Pods(api.NamespaceDefault)

	pod := loadPodOrDie("./api/examples/pod.json")
	value := strconv.Itoa(time.Now().Nanosecond())
	pod.Labels["time"] = value

	_, err := podClient.Create(pod)
	if err != nil {
		glog.Errorf("Failed to create pod: %v", err)
		return false
	}
	defer podClient.Delete(pod.Name)
	waitForPodRunning(c, pod.Name)
	pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod")
		return false
	}

	podOut, err := podClient.Get(pod.Name)
	if err != nil {
		glog.Errorf("Failed to get pod: %v", err)
		return false
	}
	value = "time" + value
	pod.Labels["time"] = value
	pod.ResourceVersion = podOut.ResourceVersion
	pod.DesiredState.Manifest.UUID = podOut.DesiredState.Manifest.UUID
	pod, err = podClient.Update(pod)
	if err != nil {
		glog.Errorf("Failed to update pod: %v", err)
		return false
	}
	waitForPodRunning(c, pod.Name)
	pods, err = podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod after update.")
		return false
	}
	glog.Infof("pod update OK")
	return true
}

// TestKubeletSendsEvent checks that kubelets and scheduler send events about pods scheduling and running.
func TestKubeletSendsEvent(c *client.Client) bool {
	provider := os.Getenv("KUBERNETES_PROVIDER")
	if provider == "" {
		glog.Errorf("unable to detect cloud type.")
		return false
	}
	if provider != "gce" {
		glog.Infof("skipping TestKubeletSendsEvent on cloud provider %s", provider)
		return true
	}

	podClient := c.Pods(api.NamespaceDefault)

	pod := loadPodOrDie("./api/examples/pod.json")
	value := strconv.Itoa(time.Now().Nanosecond())
	pod.Labels["time"] = value

	_, err := podClient.Create(pod)
	if err != nil {
		glog.Errorf("Failed to create pod: %v", err)
		return false
	}
	defer podClient.Delete(pod.Name)
	waitForPodRunning(c, pod.Name)
	pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod")
		return false
	}

	_, err = podClient.Get(pod.Name)
	if err != nil {
		glog.Errorf("Failed to get pod: %v", err)
		return false
	}

	// Check for scheduler event about the pod.
	events, err := c.Events(api.NamespaceDefault).List(
		labels.Everything(),
		labels.Set{
			"involvedObject.name":      pod.Name,
			"involvedObject.kind":      "Pod",
			"involvedObject.namespace": api.NamespaceDefault,
			"source":                   "scheduler",
			"time":                     value,
		}.AsSelector(),
	)
	if err != nil {
		glog.Error("Error while listing events:", err)
		return false
	}
	if len(events.Items) == 0 {
		glog.Error("Didn't see any scheduler events even though pod was running.")
		return false
	}
	glog.Info("Saw scheduler event for our pod.")

	// Check for kubelet event about the pod.
	events, err = c.Events(api.NamespaceDefault).List(
		labels.Everything(),
		labels.Set{
			"involvedObject.name":      pod.Name,
			"involvedObject.kind":      "BoundPod",
			"involvedObject.namespace": api.NamespaceDefault,
			"source":                   "kubelet",
		}.AsSelector(),
	)
	if err != nil {
		glog.Error("Error while listing events:", err)
		return false
	}
	if len(events.Items) == 0 {
		glog.Error("Didn't see any kubelet events even though pod was running.")
		return false
	}
	glog.Info("Saw kubelet event for our pod.")
	return true
}

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(runtime.NumCPU())
	util.ReallyCrash = true
	util.InitLogs()
	defer util.FlushLogs()

	go func() {
		defer util.FlushLogs()
		time.Sleep(3 * time.Minute)
		glog.Fatalf("This test has timed out.")
	}()

	c := loadClientOrDie()

	tests := []func(c *client.Client) bool{
		TestKubernetesROService,
		TestKubeletSendsEvent,
		// TODO(brendandburns): fix this test and re-add it: TestPodUpdate,
	}

	passed := true
	for _, test := range tests {
		testPassed := test(c)
		if !testPassed {
			passed = false
		}
		// TODO: clean up objects created during a test after the test, so cases
		// are independent.
	}
	if !passed {
		glog.Fatalf("Tests failed")
	}
}
<commit_msg>Treat unset KUBERNETES_PROVIDER as gce.<commit_after>/*
Copyright 2014 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 main

import (
	"flag"
	"io/ioutil"
	"os"
	"runtime"
	"strconv"
	"time"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/clientauth"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
	"github.com/golang/glog"
)

var (
	authConfig = flag.String("auth_config", os.Getenv("HOME")+"/.kubernetes_auth", "Path to the auth info file.")
	host       = flag.String("host", "", "The host to connect to")
)

func waitForPodRunning(c *client.Client, id string) {
	for {
		time.Sleep(5 * time.Second)
		pod, err := c.Pods(api.NamespaceDefault).Get(id)
		if err != nil {
			glog.Warningf("Get pod failed: %v", err)
			continue
		}
		if pod.CurrentState.Status == api.PodRunning {
			break
		}
		glog.Infof("Waiting for pod status to be running (%s)", pod.CurrentState.Status)
	}
}

func loadObjectOrDie(filePath string) interface{} {
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		glog.Fatalf("Failed to read pod: %v", err)
	}
	obj, err := latest.Codec.Decode(data)
	if err != nil {
		glog.Fatalf("Failed to decode pod: %v", err)
	}
	return obj
}

func loadPodOrDie(filePath string) *api.Pod {
	obj := loadObjectOrDie(filePath)
	pod, ok := obj.(*api.Pod)
	if !ok {
		glog.Fatalf("Failed to load pod: %v", obj)
	}
	return pod
}

func loadClientOrDie() *client.Client {
	config := client.Config{
		Host: *host,
	}
	auth, err := clientauth.LoadFromFile(*authConfig)
	if err != nil {
		glog.Fatalf("Error loading auth: %v", err)
	}
	config, err = auth.MergeWithConfig(config)
	if err != nil {
		glog.Fatalf("Error creating client")
	}
	c, err := client.New(&config)
	if err != nil {
		glog.Fatalf("Error creating client")
	}
	return c
}

func TestKubernetesROService(c *client.Client) bool {
	svc := api.ServiceList{}
	err := c.Get().
		Namespace("default").
		AbsPath("/api/v1beta1/proxy/services/kubernetes-ro/api/v1beta1/services").
		Do().
		Into(&svc)
	if err != nil {
		glog.Errorf("unexpected error listing services using ro service: %v", err)
		return false
	}
	var foundRW, foundRO bool
	for i := range svc.Items {
		if svc.Items[i].Name == "kubernetes" {
			foundRW = true
		}
		if svc.Items[i].Name == "kubernetes-ro" {
			foundRO = true
		}
	}
	if !foundRW {
		glog.Error("no RW service found")
	}
	if !foundRO {
		glog.Error("no RO service found")
	}
	if !foundRW || !foundRO {
		return false
	}
	return true
}

func TestPodUpdate(c *client.Client) bool {
	podClient := c.Pods(api.NamespaceDefault)

	pod := loadPodOrDie("./api/examples/pod.json")
	value := strconv.Itoa(time.Now().Nanosecond())
	pod.Labels["time"] = value

	_, err := podClient.Create(pod)
	if err != nil {
		glog.Errorf("Failed to create pod: %v", err)
		return false
	}
	defer podClient.Delete(pod.Name)
	waitForPodRunning(c, pod.Name)
	pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod")
		return false
	}

	podOut, err := podClient.Get(pod.Name)
	if err != nil {
		glog.Errorf("Failed to get pod: %v", err)
		return false
	}
	value = "time" + value
	pod.Labels["time"] = value
	pod.ResourceVersion = podOut.ResourceVersion
	pod.DesiredState.Manifest.UUID = podOut.DesiredState.Manifest.UUID
	pod, err = podClient.Update(pod)
	if err != nil {
		glog.Errorf("Failed to update pod: %v", err)
		return false
	}
	waitForPodRunning(c, pod.Name)
	pods, err = podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod after update.")
		return false
	}
	glog.Infof("pod update OK")
	return true
}

// TestKubeletSendsEvent checks that kubelets and scheduler send events about pods scheduling and running.
func TestKubeletSendsEvent(c *client.Client) bool {
	provider := os.Getenv("KUBERNETES_PROVIDER")
	if provider != "gce" {
		glog.Infof("skipping TestKubeletSendsEvent on cloud provider %s", provider)
		return true
	}
	if provider == "" {
		glog.Info("KUBERNETES_PROVIDER is unset assuming \"gce\"")
	}

	podClient := c.Pods(api.NamespaceDefault)

	pod := loadPodOrDie("./api/examples/pod.json")
	value := strconv.Itoa(time.Now().Nanosecond())
	pod.Labels["time"] = value

	_, err := podClient.Create(pod)
	if err != nil {
		glog.Errorf("Failed to create pod: %v", err)
		return false
	}
	defer podClient.Delete(pod.Name)
	waitForPodRunning(c, pod.Name)
	pods, err := podClient.List(labels.SelectorFromSet(labels.Set(map[string]string{"time": value})))
	if len(pods.Items) != 1 {
		glog.Errorf("Failed to find the correct pod")
		return false
	}

	_, err = podClient.Get(pod.Name)
	if err != nil {
		glog.Errorf("Failed to get pod: %v", err)
		return false
	}

	// Check for scheduler event about the pod.
	events, err := c.Events(api.NamespaceDefault).List(
		labels.Everything(),
		labels.Set{
			"involvedObject.name":      pod.Name,
			"involvedObject.kind":      "Pod",
			"involvedObject.namespace": api.NamespaceDefault,
			"source":                   "scheduler",
			"time":                     value,
		}.AsSelector(),
	)
	if err != nil {
		glog.Error("Error while listing events:", err)
		return false
	}
	if len(events.Items) == 0 {
		glog.Error("Didn't see any scheduler events even though pod was running.")
		return false
	}
	glog.Info("Saw scheduler event for our pod.")

	// Check for kubelet event about the pod.
	events, err = c.Events(api.NamespaceDefault).List(
		labels.Everything(),
		labels.Set{
			"involvedObject.name":      pod.Name,
			"involvedObject.kind":      "BoundPod",
			"involvedObject.namespace": api.NamespaceDefault,
			"source":                   "kubelet",
		}.AsSelector(),
	)
	if err != nil {
		glog.Error("Error while listing events:", err)
		return false
	}
	if len(events.Items) == 0 {
		glog.Error("Didn't see any kubelet events even though pod was running.")
		return false
	}
	glog.Info("Saw kubelet event for our pod.")
	return true
}

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(runtime.NumCPU())
	util.ReallyCrash = true
	util.InitLogs()
	defer util.FlushLogs()

	go func() {
		defer util.FlushLogs()
		time.Sleep(3 * time.Minute)
		glog.Fatalf("This test has timed out.")
	}()

	c := loadClientOrDie()

	tests := []func(c *client.Client) bool{
		TestKubernetesROService,
		TestKubeletSendsEvent,
		// TODO(brendandburns): fix this test and re-add it: TestPodUpdate,
	}

	passed := true
	for _, test := range tests {
		testPassed := test(c)
		if !testPassed {
			passed = false
		}
		// TODO: clean up objects created during a test after the test, so cases
		// are independent.
	}
	if !passed {
		glog.Fatalf("Tests failed")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"code.google.com/p/rsc/qr"
	"github.com/mattn/go-colorable"
	"github.com/jessevdk/go-flags"
	"os"

	"github.com/fumiyas/qrc/lib"
	"github.com/fumiyas/qrc/tty"
)

type cmdOptions struct {
	Help    bool `short:"h" long:"help" description:"show this help message"`
	Inverse bool `short:"i" long:"invert" description:"invert color"`
}

func showHelp() {
	const v = `Usage: qrc [OPTIONS] [TEXT]

Options:
  -h, --help
    Show this help message
  -i, --invert
    Invert color

Text examples:
  URLTO:http://www.example.jp/
  MAILTO:foobar@example.jp
  WIFI:S:myssid;T:WPA;P:pass123;;
`

	os.Stderr.Write([]byte(v))
}

func main() {
	ret := 0
	defer func() { os.Exit(ret) }()

	opts := &cmdOptions{}
	optsParser := flags.NewParser(opts, flags.PrintErrors)
	args, err := optsParser.Parse()
	if err != nil || len(args) > 1 {
		showHelp()
		ret = 1
		return
	}
	if opts.Help {
		showHelp()
		return
	}

	var text string
	if len(args) == 1 {
		text = args[0]
	} else {
		// FIXME: Read all input
		rd := bufio.NewReaderSize(os.Stdin, 1024)
		text_bytes, _, _ := rd.ReadLine()
		text = string(text_bytes)
	}

	code, _ := qr.Encode(text, qr.L)

	da1, err := tty.GetDeviceAttributes1(os.Stdout)
	if err == nil && da1[tty.DA1_SIXEL] {
		qrc.PrintSixel(os.Stdout, code, opts.Inverse)
	} else {
		stdout := colorable.NewColorableStdout()
		qrc.PrintAA(stdout, code, opts.Inverse)
	}
}
<commit_msg>Fix example text for HTTP URL<commit_after>package main

import (
	"bufio"
	"code.google.com/p/rsc/qr"
	"github.com/mattn/go-colorable"
	"github.com/jessevdk/go-flags"
	"os"

	"github.com/fumiyas/qrc/lib"
	"github.com/fumiyas/qrc/tty"
)

type cmdOptions struct {
	Help    bool `short:"h" long:"help" description:"show this help message"`
	Inverse bool `short:"i" long:"invert" description:"invert color"`
}

func showHelp() {
	const v = `Usage: qrc [OPTIONS] [TEXT]

Options:
  -h, --help
    Show this help message
  -i, --invert
    Invert color

Text examples:
  http://www.example.jp/
  MAILTO:foobar@example.jp
  WIFI:S:myssid;T:WPA;P:pass123;;
`

	os.Stderr.Write([]byte(v))
}

func main() {
	ret := 0
	defer func() { os.Exit(ret) }()

	opts := &cmdOptions{}
	optsParser := flags.NewParser(opts, flags.PrintErrors)
	args, err := optsParser.Parse()
	if err != nil || len(args) > 1 {
		showHelp()
		ret = 1
		return
	}
	if opts.Help {
		showHelp()
		return
	}

	var text string
	if len(args) == 1 {
		text = args[0]
	} else {
		// FIXME: Read all input
		rd := bufio.NewReaderSize(os.Stdin, 1024)
		text_bytes, _, _ := rd.ReadLine()
		text = string(text_bytes)
	}

	code, _ := qr.Encode(text, qr.L)

	da1, err := tty.GetDeviceAttributes1(os.Stdout)
	if err == nil && da1[tty.DA1_SIXEL] {
		qrc.PrintSixel(os.Stdout, code, opts.Inverse)
	} else {
		stdout := colorable.NewColorableStdout()
		qrc.PrintAA(stdout, code, opts.Inverse)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/voidint/gbb/build"
)

var (
	// Version 版本号
	Version = "0.3.0"
)

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print version information",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(build.Version(fmt.Sprintf("gbb version %s", Version)))
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>Upgrade version<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/voidint/gbb/build"
)

var (
	// Version 版本号
	Version = "0.4.0"
)

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print version information",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(build.Version(fmt.Sprintf("gbb version %s", Version)))
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_version() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_version,
		UsageLine: "version",
		Short:     "print version and exit",
		Long: `
print version and exit.

ex:
 $ hwaf version
 hwaf-20121212
`,
		Flag: *flag.NewFlagSet("hwaf-version", flag.ExitOnError),
	}
	return cmd
}

func hwaf_run_cmd_version(cmd *commander.Command, args []string) {
	fmt.Printf("hwaf-20130201\n")
}

// EOF
<commit_msg>version: 20130205<commit_after>package main

import (
	"fmt"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_version() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_version,
		UsageLine: "version",
		Short:     "print version and exit",
		Long: `
print version and exit.

ex:
 $ hwaf version
 hwaf-20121212
`,
		Flag: *flag.NewFlagSet("hwaf-version", flag.ExitOnError),
	}
	return cmd
}

func hwaf_run_cmd_version(cmd *commander.Command, args []string) {
	fmt.Printf("hwaf-20130205\n")
}

// EOF
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	"github.com/iron-io/functions_go"
	"github.com/urfave/cli"
	"golang.org/x/crypto/ssh/terminal"
)

type routesCmd struct {
	*functions.RoutesApi
}

func routes() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	flags := append(confFlags(&r.Configuration), []cli.Flag{}...)
	return cli.Command{
		Name:      "routes",
		Usage:     "list routes",
		ArgsUsage: "fnclt routes",
		Flags:     flags,
		Action:    r.list,
		Subcommands: []cli.Command{
			{
				Name:      "call",
				Usage:     "call a route",
				ArgsUsage: "appName /path",
				Action:    r.call,
				Flags:     append(flags, runflags()...),
			},
			{
				Name:      "create",
				Usage:     "create a route",
				ArgsUsage: "appName /path image/name",
				Action:    r.create,
			},
			{
				Name:      "delete",
				Usage:     "delete a route",
				ArgsUsage: "appName /path",
				Action:    r.delete,
			},
		},
	}
}

func call() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	flags := append([]cli.Flag{}, confFlags(&r.Configuration)...)
	flags = append(flags, runflags()...)
	return cli.Command{
		Name:      "call",
		Usage:     "call a remote function",
		ArgsUsage: "appName /path",
		Flags:     flags,
		Action:    r.call,
	}
}

func (a *routesCmd) list(c *cli.Context) error {
	if c.Args().First() == "" {
		return errors.New("error: routes listing takes one argument, an app name")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	wrapper, _, err := a.AppsAppRoutesGet(appName)
	if err != nil {
		return fmt.Errorf("error getting routes: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
	fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
	for _, route := range wrapper.Routes {
		u, err := url.Parse("../")
		u.Path = path.Join(u.Path, "r", appName, route.Path)
		if err != nil {
			return fmt.Errorf("error parsing functions route path: %v", err)
		}

		fmt.Fprint(w, route.Path, "\t", route.Image, "\t", baseURL.ResolveReference(u).String(), "\n")
	}
	w.Flush()

	return nil
}

func (a *routesCmd) call(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a route")
	}

	resetBasePath(&a.Configuration)

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)

	u, err := url.Parse("../")
	u.Path = path.Join(u.Path, "r", appName, route)

	var content io.Reader
	if !terminal.IsTerminal(int(os.Stdin.Fd())) {
		content = os.Stdin
	}

	req, err := http.NewRequest("POST", baseURL.ResolveReference(u).String(), content)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	envAsHeader(req, c.StringSlice("e"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}

	io.Copy(os.Stdout, resp.Body)
	return nil
}

func envAsHeader(req *http.Request, selectedEnv []string) {
	detectedEnv := os.Environ()
	if len(selectedEnv) > 0 {
		detectedEnv = selectedEnv
	}

	for _, e := range detectedEnv {
		kv := strings.Split(e, "=")
		name := kv[0]
		req.Header.Set(name, os.Getenv(name))
	}
}

func (a *routesCmd) create(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" {
		return errors.New("error: routes listing takes three arguments: an app name, a route path and an image")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	image := c.Args().Get(2)
	body := functions.RouteWrapper{
		Route: functions.Route{
			AppName: appName,
			Path:    route,
			Image:   image,
		},
	}
	wrapper, _, err := a.AppsAppRoutesPost(appName, body)
	if err != nil {
		return fmt.Errorf("error creating route: %v", err)
	}
	if wrapper.Route.Path == "" || wrapper.Route.Image == "" {
		return fmt.Errorf("could not create this route (%s at %s), check if route path is correct", route, appName)
	}

	fmt.Println(wrapper.Route.Path, "created with", wrapper.Route.Image)
	return nil
}

func (a *routesCmd) delete(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a path")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	_, err := a.AppsAppRoutesRouteDelete(appName, route)
	if err != nil {
		return fmt.Errorf("error deleting route: %v", err)
	}

	fmt.Println(route, "deleted")
	return nil
}
<commit_msg>fix envAsHeader to set the req Header from kv[1] instead of os.Getenv(name) (#225)<commit_after>package main

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"
	"text/tabwriter"

	"github.com/iron-io/functions_go"
	"github.com/urfave/cli"
	"golang.org/x/crypto/ssh/terminal"
)

type routesCmd struct {
	*functions.RoutesApi
}

func routes() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	flags := append(confFlags(&r.Configuration), []cli.Flag{}...)
	return cli.Command{
		Name:      "routes",
		Usage:     "list routes",
		ArgsUsage: "fnclt routes",
		Flags:     flags,
		Action:    r.list,
		Subcommands: []cli.Command{
			{
				Name:      "call",
				Usage:     "call a route",
				ArgsUsage: "appName /path",
				Action:    r.call,
				Flags:     append(flags, runflags()...),
			},
			{
				Name:      "create",
				Usage:     "create a route",
				ArgsUsage: "appName /path image/name",
				Action:    r.create,
			},
			{
				Name:      "delete",
				Usage:     "delete a route",
				ArgsUsage: "appName /path",
				Action:    r.delete,
			},
		},
	}
}

func call() cli.Command {
	r := routesCmd{RoutesApi: functions.NewRoutesApi()}

	flags := append([]cli.Flag{}, confFlags(&r.Configuration)...)
	flags = append(flags, runflags()...)
	return cli.Command{
		Name:      "call",
		Usage:     "call a remote function",
		ArgsUsage: "appName /path",
		Flags:     flags,
		Action:    r.call,
	}
}

func (a *routesCmd) list(c *cli.Context) error {
	if c.Args().First() == "" {
		return errors.New("error: routes listing takes one argument, an app name")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	wrapper, _, err := a.AppsAppRoutesGet(appName)
	if err != nil {
		return fmt.Errorf("error getting routes: %v", err)
	}

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	w := tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
	fmt.Fprint(w, "path", "\t", "image", "\t", "endpoint", "\n")
	for _, route := range wrapper.Routes {
		u, err := url.Parse("../")
		u.Path = path.Join(u.Path, "r", appName, route.Path)
		if err != nil {
			return fmt.Errorf("error parsing functions route path: %v", err)
		}

		fmt.Fprint(w, route.Path, "\t", route.Image, "\t", baseURL.ResolveReference(u).String(), "\n")
	}
	w.Flush()

	return nil
}

func (a *routesCmd) call(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a route")
	}

	resetBasePath(&a.Configuration)

	baseURL, err := url.Parse(a.Configuration.BasePath)
	if err != nil {
		return fmt.Errorf("error parsing base path: %v", err)
	}

	appName := c.Args().Get(0)
	route := c.Args().Get(1)

	u, err := url.Parse("../")
	u.Path = path.Join(u.Path, "r", appName, route)

	var content io.Reader
	if !terminal.IsTerminal(int(os.Stdin.Fd())) {
		content = os.Stdin
	}

	req, err := http.NewRequest("POST", baseURL.ResolveReference(u).String(), content)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")

	envAsHeader(req, c.StringSlice("e"))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return fmt.Errorf("error running route: %v", err)
	}

	io.Copy(os.Stdout, resp.Body)
	return nil
}

func envAsHeader(req *http.Request, selectedEnv []string) {
	detectedEnv := os.Environ()
	if len(selectedEnv) > 0 {
		detectedEnv = selectedEnv
	}

	for _, e := range detectedEnv {
		kv := strings.Split(e, "=")
		name := kv[0]
		req.Header.Set(name, kv[1])
	}
}

func (a *routesCmd) create(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" || c.Args().Get(2) == "" {
		return errors.New("error: routes listing takes three arguments: an app name, a route path and an image")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	image := c.Args().Get(2)
	body := functions.RouteWrapper{
		Route: functions.Route{
			AppName: appName,
			Path:    route,
			Image:   image,
		},
	}
	wrapper, _, err := a.AppsAppRoutesPost(appName, body)
	if err != nil {
		return fmt.Errorf("error creating route: %v", err)
	}
	if wrapper.Route.Path == "" || wrapper.Route.Image == "" {
		return fmt.Errorf("could not create this route (%s at %s), check if route path is correct", route, appName)
	}

	fmt.Println(wrapper.Route.Path, "created with", wrapper.Route.Image)
	return nil
}

func (a *routesCmd) delete(c *cli.Context) error {
	if c.Args().Get(0) == "" || c.Args().Get(1) == "" {
		return errors.New("error: routes listing takes three arguments: an app name and a path")
	}

	resetBasePath(&a.Configuration)

	appName := c.Args().Get(0)
	route := c.Args().Get(1)
	_, err := a.AppsAppRoutesRouteDelete(appName, route)
	if err != nil {
		return fmt.Errorf("error deleting route: %v", err)
	}

	fmt.Println(route, "deleted")
	return nil
}
<|endoftext|>


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

package integration

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"time"

	"gopkg.in/check.v1"
)

var (
	T            = NewCommand("tsuru").WithArgs
	allPlatforms = []string{
		"tsuru/python",
		"tsuru/go",
		"tsuru/buildpack",
		"tsuru/cordova",
		"tsuru/elixir",
		"tsuru/java",
		"tsuru/nodejs",
		"tsuru/php",
		"tsuru/play",
		"tsuru/pypy",
		"tsuru/python3",
		"tsuru/ruby",
		"tsuru/static",
	}
	allProvisioners = []string{
		"docker",
		"swarm",
	}
	flows = []ExecFlow{
		platformsToInstall(),
		installerConfigTest(),
		installerTest(),
		targetTest(),
		loginTest(),
		removeInstallNodes(),
		quotaTest(),
		teamTest(),
		poolAdd(),
		platformAdd(),
		exampleApps(),
	}
)

var installerConfig = `driver:
  name: virtualbox
  options:
    virtualbox-cpu-count: 2
    virtualbox-memory: 2048
hosts:
  apps:
    size: 2
components:
  tsuru:
    version: latest
    install-dashboard: false
`

func platformsToInstall() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platformimages"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		for _, platImg := range allPlatforms {
			env.Add("platformimages", platImg)
		}
	}
	return flow
}

func installerConfigTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"installerconfig"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		f, err := ioutil.TempFile("", "installer-config")
		c.Assert(err, check.IsNil)
		defer f.Close()
		f.Write([]byte(installerConfig))
		env.Set("installerconfig", f.Name())
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := NewCommand("rm", "{{.installerconfig}}").Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func installerTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"targetaddr"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("install", "--config", "{{.installerconfig}}").WithTimeout(30 * time.Minute).Run(env)
		c.Assert(res, ResultOk)
		regex := regexp.MustCompile(`(?si).*Core Hosts:.*?([\d.]+)\s.*`)
		parts := regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetHost := parts[1]
		regex = regexp.MustCompile(`(?si).*Tsuru API.*?\|\s(\d+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetPort := parts[1]
		env.Set("targetaddr", fmt.Sprintf("http://%s:%s", targetHost, targetPort))
		regex = regexp.MustCompile(`\| (https?[^\s]+?) \|`)
		allParts := regex.FindAllStringSubmatch(res.Stdout.String(), -1)
		for _, parts = range allParts {
			c.Assert(parts, check.HasLen, 2)
			env.Add("nodeopts", fmt.Sprintf("--register address=%s --cacert ~/.tsuru/installs/tsuru/certs/ca.pem --clientcert ~/.tsuru/installs/tsuru/certs/cert.pem --clientkey ~/.tsuru/installs/tsuru/certs/key.pem", parts[1]))
			env.Add("nodestoremove", parts[1])
		}
		regex = regexp.MustCompile(`Username: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		env.Set("adminuser", parts[1])
		regex = regexp.MustCompile(`Password: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		env.Set("adminpassword", parts[1])
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("uninstall", "-y").Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func targetTest() ExecFlow {
	flow := ExecFlow{}
	flow.forward = func(c *check.C, env *Environment) {
		targetName := "integration-target"
		res := T("target-add", targetName, "{{.targetaddr}}").Run(env)
		c.Assert(res, ResultOk)
		res = T("target-list").Run(env)
		c.Assert(res, ResultMatches, Expected{Stdout: `\s+` + targetName + ` .*`})
		res = T("target-set", targetName).Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func loginTest() ExecFlow {
	flow := ExecFlow{}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("login", "{{.adminuser}}").WithInput("{{.adminpassword}}").Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func removeInstallNodes() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodestoremove",
		},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("node-remove", "-y", "--no-rebalance", "{{.node}}").Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func quotaTest() ExecFlow {
	flow := ExecFlow{
		requires: []string{"adminuser"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("user-quota-change", "{{.adminuser}}", "100").Run(env)
		c.Assert(res, ResultOk)
		res = T("user-quota-view", "{{.adminuser}}").Run(env)
		c.Assert(res, ResultMatches, Expected{Stdout: `(?s)Apps usage.*/100`})
	}
	return flow
}

func teamTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"team"},
	}
	teamName := "integration-team"
	flow.forward = func(c *check.C, env *Environment) {
		res := T("team-create", teamName).Run(env)
		c.Assert(res, ResultOk)
		env.Set("team", teamName)
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("team-remove", "-y", teamName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func poolAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"poolnames"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		for _, prov := range allProvisioners {
			poolName := "ipool-" + prov
			res := T("pool-add", "--provisioner", prov, poolName).Run(env)
			c.Assert(res, ResultOk)
			env.Add("poolnames", poolName)
			res = T("pool-teams-add", poolName, "{{.team}}").Run(env)
			c.Assert(res, ResultOk)
			res = T("node-add", "{{.nodeopts}}", "pool="+poolName).Run(env)
			c.Assert(res, ResultOk)
			res = T("event-list").Run(env)
			c.Assert(res, ResultOk)
			nodeopts := env.All("nodeopts")
			env.Set("nodeopts", append(nodeopts[1:], nodeopts[0])...)
			regex := regexp.MustCompile(`node.create.*?node:\s+(.*?)\s+`)
			parts := regex.FindStringSubmatch(res.Stdout.String())
			c.Assert(parts, check.HasLen, 2)
			env.Add("nodeaddrs", parts[1])
			regex = regexp.MustCompile(parts[1] + `.*?ready`)
			ok := retry(time.Minute, func() bool {
				res = T("node-list").Run(env)
				return regex.MatchString(res.Stdout.String())
			})
			c.Assert(ok, check.Equals, true, check.Commentf("node not ready after 1 minute: %v", res))
		}
	}
	flow.backward = func(c *check.C, env *Environment) {
		for _, node := range env.All("nodeaddrs") {
			res := T("node-remove", "-y", "--no-rebalance", node).Run(env)
			c.Check(res, ResultOk)
		}
		for _, prov := range allProvisioners {
			poolName := "ipool-" + prov
			res := T("pool-teams-remove", poolName, "{{.team}}").Run(env)
			c.Check(res, ResultOk)
			res = T("pool-remove", "-y", poolName).Run(env)
			c.Check(res, ResultOk)
		}
	}
	return flow
}

func platformAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platforms"},
		matrix: map[string]string{
			"platimg": "platformimages",
		},
		parallel: true,
	}
	flow.forward = func(c *check.C, env *Environment) {
		img := env.Get("platimg")
		suffix := img[strings.LastIndex(img, "/")+1:]
		platName := "iplat-" + suffix
		res := T("platform-add", platName, "-i", img).WithTimeout(15 * time.Minute).Run(env)
		c.Assert(res, ResultOk)
		env.Add("platforms", platName)
		res = T("platform-list").Run(env)
		c.Assert(res, ResultOk)
		c.Assert(res, ResultMatches, Expected{Stdout: "(?s).*- " + platName + ".*"})
	}
	flow.backward = func(c *check.C, env *Environment) {
		img := env.Get("platimg")
		suffix := img[strings.LastIndex(img, "/")+1:]
		platName := "iplat-" + suffix
		res := T("platform-remove", "-y", platName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func exampleApps() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"pool": "poolnames",
			"plat": "platforms",
		},
		parallel: true,
	}
	appName := "iapp-{{.plat}}-{{.pool}}"
	flow.forward = func(c *check.C, env *Environment) {
		res := T("app-create", appName, "{{.plat}}", "-t", "{{.team}}", "-o", "{{.pool}}").Run(env)
		c.Assert(res, ResultOk)
		res = T("app-info", "-a", appName).Run(env)
		c.Assert(res, ResultOk)
		platRE := regexp.MustCompile(`(?s)Platform: (.*?)\n`)
		parts := platRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		lang := strings.Replace(parts[1], "iplat-", "", -1)
		res = T("app-deploy", "-a", appName, "{{.examplesdir}}/"+lang+"/").Run(env)
		c.Assert(res, ResultOk)
		res = T("app-info", "-a", appName).Run(env)
		c.Assert(res, ResultOk)
		addrRE := regexp.MustCompile(`(?s)Address: (.*?)\n`)
		parts = addrRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		cmd := NewCommand("curl", "-sSf", "http://"+parts[1])
		ok := retry(5*time.Minute, func() bool {
			res = cmd.Run(env)
			return res.ExitCode == 0
		})
		c.Assert(ok, check.Equals, true, check.Commentf("invalid result: %v", res))
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("app-remove", "-y", "-a", appName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func (s *S) TestBase(c *check.C) {
	env := NewEnvironment()
	if !env.Has("enabled") {
		return
	}
	var executedFlows []*ExecFlow
	defer func() {
		for i := len(executedFlows) - 1; i >= 0; i-- {
			executedFlows[i].Rollback(c, env)
		}
	}()
	for i := range flows {
		f := &flows[i]
		if len(f.provides) > 0 {
			providesAll := true
			for _, envVar := range f.provides {
				if env.Get(envVar) == "" {
					providesAll = false
					break
				}
			}
			if providesAll {
				continue
			}
		}
		executedFlows = append(executedFlows, f)
		f.Run(c, env)
	}
}
<commit_msg>integration: changes install for compose based method<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package integration

import (
	"fmt"
	"io/ioutil"
	"regexp"
	"strings"
	"time"

	"gopkg.in/check.v1"
)

var (
	T            = NewCommand("tsuru").WithArgs
	allPlatforms = []string{
		"tsuru/python",
		"tsuru/go",
		"tsuru/buildpack",
		"tsuru/cordova",
		"tsuru/elixir",
		"tsuru/java",
		"tsuru/nodejs",
		"tsuru/php",
		"tsuru/play",
		"tsuru/pypy",
		"tsuru/python3",
		"tsuru/ruby",
		"tsuru/static",
	}
	allProvisioners = []string{
		"docker",
		"swarm",
	}
	flows = []ExecFlow{
		platformsToInstall(),
		installerConfigTest(),
		installerTest(),
		targetTest(),
		loginTest(),
		removeInstallNodes(),
		quotaTest(),
		teamTest(),
		poolAdd(),
		platformAdd(),
		exampleApps(),
	}
)

var installerConfig = `driver:
  name: virtualbox
  options:
    virtualbox-cpu-count: 2
    virtualbox-memory: 2048
hosts:
  apps:
    size: 2
components:
    install-dashboard: false
`

func platformsToInstall() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platformimages"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		for _, platImg := range allPlatforms {
			env.Add("platformimages", platImg)
		}
	}
	return flow
}

func installerConfigTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"installerconfig", "installercompose"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		f, err := ioutil.TempFile("", "installer-config")
		c.Assert(err, check.IsNil)
		defer f.Close()
		composeFile, err := ioutil.TempFile("", "installer-compose")
		c.Assert(err, check.IsNil)
		defer composeFile.Close()
		res := T("install-config-init", f.Name(), composeFile.Name()).Run(env)
		c.Assert(res, ResultOk)
		f.Write([]byte(installerConfig))
		composeData, err := ioutil.ReadFile(composeFile.Name())
		c.Assert(err, check.IsNil)
		composeData = []byte(strings.Replace(string(composeData), "tsuru/api:v1", "tsuru/api:latest", 1))
		err = ioutil.WriteFile(composeFile.Name(), composeData, 0644)
		c.Assert(err, check.IsNil)
		env.Set("installerconfig", f.Name())
		env.Set("installercompose", composeFile.Name())
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := NewCommand("rm", "{{.installerconfig}}").Run(env)
		c.Check(res, ResultOk)
		res = NewCommand("rm", "{{.installercompose}}").Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func installerTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"targetaddr"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("install", "--config", "{{.installerconfig}}", "--compose", "{{.installercompose}}").WithTimeout(30 * time.Minute).Run(env)
		c.Assert(res, ResultOk)
		regex := regexp.MustCompile(`(?si).*Core Hosts:.*?([\d.]+)\s.*`)
		parts := regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetHost := parts[1]
		regex = regexp.MustCompile(`(?si).*tsuru_tsuru.*?\|\s(\d+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		targetPort := parts[1]
		env.Set("targetaddr", fmt.Sprintf("http://%s:%s", targetHost, targetPort))
		regex = regexp.MustCompile(`\| (https?[^\s]+?) \|`)
		allParts := regex.FindAllStringSubmatch(res.Stdout.String(), -1)
		for _, parts = range allParts {
			c.Assert(parts, check.HasLen, 2)
			env.Add("nodeopts", fmt.Sprintf("--register address=%s --cacert ~/.tsuru/installs/tsuru/certs/ca.pem --clientcert ~/.tsuru/installs/tsuru/certs/cert.pem --clientkey ~/.tsuru/installs/tsuru/certs/key.pem", parts[1]))
			env.Add("nodestoremove", parts[1])
		}
		regex = regexp.MustCompile(`Username: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		env.Set("adminuser", parts[1])
		regex = regexp.MustCompile(`Password: ([[:print:]]+)`)
		parts = regex.FindStringSubmatch(res.Stdout.String())
		env.Set("adminpassword", parts[1])
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("uninstall", "-y").Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func targetTest() ExecFlow {
	flow := ExecFlow{}
	flow.forward = func(c *check.C, env *Environment) {
		targetName := "integration-target"
		res := T("target-add", targetName, "{{.targetaddr}}").Run(env)
		c.Assert(res, ResultOk)
		res = T("target-list").Run(env)
		c.Assert(res, ResultMatches, Expected{Stdout: `\s+` + targetName + ` .*`})
		res = T("target-set", targetName).Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func loginTest() ExecFlow {
	flow := ExecFlow{}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("login", "{{.adminuser}}").WithInput("{{.adminpassword}}").Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func removeInstallNodes() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"node": "nodestoremove",
		},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("node-remove", "-y", "--no-rebalance", "{{.node}}").Run(env)
		c.Assert(res, ResultOk)
	}
	return flow
}

func quotaTest() ExecFlow {
	flow := ExecFlow{
		requires: []string{"adminuser"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		res := T("user-quota-change", "{{.adminuser}}", "100").Run(env)
		c.Assert(res, ResultOk)
		res = T("user-quota-view", "{{.adminuser}}").Run(env)
		c.Assert(res, ResultMatches, Expected{Stdout: `(?s)Apps usage.*/100`})
	}
	return flow
}

func teamTest() ExecFlow {
	flow := ExecFlow{
		provides: []string{"team"},
	}
	teamName := "integration-team"
	flow.forward = func(c *check.C, env *Environment) {
		res := T("team-create", teamName).Run(env)
		c.Assert(res, ResultOk)
		env.Set("team", teamName)
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("team-remove", "-y", teamName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func poolAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"poolnames"},
	}
	flow.forward = func(c *check.C, env *Environment) {
		for _, prov := range allProvisioners {
			poolName := "ipool-" + prov
			res := T("pool-add", "--provisioner", prov, poolName).Run(env)
			c.Assert(res, ResultOk)
			env.Add("poolnames", poolName)
			res = T("pool-teams-add", poolName, "{{.team}}").Run(env)
			c.Assert(res, ResultOk)
			res = T("node-add", "{{.nodeopts}}", "pool="+poolName).Run(env)
			c.Assert(res, ResultOk)
			res = T("event-list").Run(env)
			c.Assert(res, ResultOk)
			nodeopts := env.All("nodeopts")
			env.Set("nodeopts", append(nodeopts[1:], nodeopts[0])...)
			regex := regexp.MustCompile(`node.create.*?node:\s+(.*?)\s+`)
			parts := regex.FindStringSubmatch(res.Stdout.String())
			c.Assert(parts, check.HasLen, 2)
			env.Add("nodeaddrs", parts[1])
			regex = regexp.MustCompile(parts[1] + `.*?ready`)
			ok := retry(time.Minute, func() bool {
				res = T("node-list").Run(env)
				return regex.MatchString(res.Stdout.String())
			})
			c.Assert(ok, check.Equals, true, check.Commentf("node not ready after 1 minute: %v", res))
		}
	}
	flow.backward = func(c *check.C, env *Environment) {
		for _, node := range env.All("nodeaddrs") {
			res := T("node-remove", "-y", "--no-rebalance", node).Run(env)
			c.Check(res, ResultOk)
		}
		for _, prov := range allProvisioners {
			poolName := "ipool-" + prov
			res := T("pool-teams-remove", poolName, "{{.team}}").Run(env)
			c.Check(res, ResultOk)
			res = T("pool-remove", "-y", poolName).Run(env)
			c.Check(res, ResultOk)
		}
	}
	return flow
}

func platformAdd() ExecFlow {
	flow := ExecFlow{
		provides: []string{"platforms"},
		matrix: map[string]string{
			"platimg": "platformimages",
		},
		parallel: true,
	}
	flow.forward = func(c *check.C, env *Environment) {
		img := env.Get("platimg")
		suffix := img[strings.LastIndex(img, "/")+1:]
		platName := "iplat-" + suffix
		res := T("platform-add", platName, "-i", img).WithTimeout(15 * time.Minute).Run(env)
		c.Assert(res, ResultOk)
		env.Add("platforms", platName)
		res = T("platform-list").Run(env)
		c.Assert(res, ResultOk)
		c.Assert(res, ResultMatches, Expected{Stdout: "(?s).*- " + platName + ".*"})
	}
	flow.backward = func(c *check.C, env *Environment) {
		img := env.Get("platimg")
		suffix := img[strings.LastIndex(img, "/")+1:]
		platName := "iplat-" + suffix
		res := T("platform-remove", "-y", platName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func exampleApps() ExecFlow {
	flow := ExecFlow{
		matrix: map[string]string{
			"pool": "poolnames",
			"plat": "platforms",
		},
		parallel: true,
	}
	appName := "iapp-{{.plat}}-{{.pool}}"
	flow.forward = func(c *check.C, env *Environment) {
		res := T("app-create", appName, "{{.plat}}", "-t", "{{.team}}", "-o", "{{.pool}}").Run(env)
		c.Assert(res, ResultOk)
		res = T("app-info", "-a", appName).Run(env)
		c.Assert(res, ResultOk)
		platRE := regexp.MustCompile(`(?s)Platform: (.*?)\n`)
		parts := platRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		lang := strings.Replace(parts[1], "iplat-", "", -1)
		res = T("app-deploy", "-a", appName, "{{.examplesdir}}/"+lang+"/").Run(env)
		c.Assert(res, ResultOk)
		res = T("app-info", "-a", appName).Run(env)
		c.Assert(res, ResultOk)
		addrRE := regexp.MustCompile(`(?s)Address: (.*?)\n`)
		parts = addrRE.FindStringSubmatch(res.Stdout.String())
		c.Assert(parts, check.HasLen, 2)
		cmd := NewCommand("curl", "-sSf", "http://"+parts[1])
		ok := retry(5*time.Minute, func() bool {
			res = cmd.Run(env)
			return res.ExitCode == 0
		})
		c.Assert(ok, check.Equals, true, check.Commentf("invalid result: %v", res))
	}
	flow.backward = func(c *check.C, env *Environment) {
		res := T("app-remove", "-y", "-a", appName).Run(env)
		c.Check(res, ResultOk)
	}
	return flow
}

func (s *S) TestBase(c *check.C) {
	env := NewEnvironment()
	if !env.Has("enabled") {
		return
	}
	var executedFlows []*ExecFlow
	defer func() {
		for i := len(executedFlows) - 1; i >= 0; i-- {
			executedFlows[i].Rollback(c, env)
		}
	}()
	for i := range flows {
		f := &flows[i]
		if len(f.provides) > 0 {
			providesAll := true
			for _, envVar := range f.provides {
				if env.Get(envVar) == "" {
					providesAll = false
					break
				}
			}
			if providesAll {
				continue
			}
		}
		executedFlows = append(executedFlows, f)
		f.Run(c, env)
	}
}
<|endoftext|>


<commit_before>// This file was automatically generated by "compat-table.js"

package compat

type Engine uint8

const (
	Chrome Engine = iota
	Edge
	ES
	Firefox
	IOS
	Node
	Safari
)

func (e Engine) String() string {
	switch e {
	case Chrome:
		return "chrome"
	case Edge:
		return "edge"
	case ES:
		return "es"
	case Firefox:
		return "firefox"
	case IOS:
		return "ios"
	case Node:
		return "node"
	case Safari:
		return "safari"
	}
	return ""
}

type JSFeature uint64

const (
	ArbitraryModuleNamespaceNames JSFeature = 1 << iota
	ArraySpread
	Arrow
	AsyncAwait
	AsyncGenerator
	BigInt
	Class
	ClassField
	ClassPrivateAccessor
	ClassPrivateBrandCheck
	ClassPrivateField
	ClassPrivateMethod
	ClassPrivateStaticAccessor
	ClassPrivateStaticField
	ClassPrivateStaticMethod
	ClassStaticField
	Const
	DefaultArgument
	Destructuring
	DynamicImport
	ExponentOperator
	ExportStarAs
	ForAwait
	ForOf
	Generator
	Hashbang
	ImportAssertions
	ImportMeta
	Let
	LogicalAssignment
	NestedRestBinding
	NewTarget
	NullishCoalescing
	ObjectAccessors
	ObjectExtensions
	ObjectRestSpread
	OptionalCatchBinding
	OptionalChain
	RestArgument
	TemplateLiteral
	TopLevelAwait
	UnicodeEscapes
)

func (features JSFeature) Has(feature JSFeature) bool {
	return (features & feature) != 0
}

var jsTable = map[JSFeature]map[Engine][]int{
	ArbitraryModuleNamespaceNames: {
		Chrome: {90},
		Node:   {16},
	},
	ArraySpread: {
		Chrome:  {46},
		Edge:    {13},
		ES:      {2015},
		Firefox: {36},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	Arrow: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	AsyncAwait: {
		Chrome:  {55},
		Edge:    {15},
		ES:      {2017},
		Firefox: {52},
		IOS:     {11},
		Node:    {7, 6},
		Safari:  {11},
	},
	AsyncGenerator: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	BigInt: {
		Chrome:  {67},
		Edge:    {79},
		ES:      {2020},
		Firefox: {68},
		IOS:     {14},
		Node:    {10, 4},
		Safari:  {14},
	},
	Class: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	ClassField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {69},
		IOS:     {14},
		Node:    {12, 0},
		Safari:  {14},
	},
	ClassPrivateAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateBrandCheck: {
		Chrome:  {91},
		Firefox: {90},
	},
	ClassPrivateField: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {14, 1},
	},
	ClassPrivateMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateStaticAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateStaticField: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {90},
		IOS:     {15},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	ClassPrivateStaticMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassStaticField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {75},
		IOS:     {15},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	Const: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	DefaultArgument: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Destructuring: {
		Chrome:  {51},
		Edge:    {18},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	DynamicImport: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2015},
		Firefox: {67},
		IOS:     {11},
		Node:    {13, 2},
		Safari:  {11, 1},
	},
	ExponentOperator: {
		Chrome:  {52},
		Edge:    {14},
		ES:      {2016},
		Firefox: {52},
		IOS:     {10, 3},
		Node:    {7},
		Safari:  {10, 1},
	},
	ExportStarAs: {
		Chrome:  {72},
		Edge:    {79},
		ES:      {2020},
		Firefox: {80},
		Node:    {12},
	},
	ForAwait: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	ForOf: {
		Chrome:  {51},
		Edge:    {15},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	Generator: {
		Chrome:  {50},
		Edge:    {13},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Hashbang: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {67},
		IOS:     {13, 4},
		Node:    {12, 0},
		Safari:  {13, 1},
	},
	ImportAssertions: {
		Chrome: {91},
	},
	ImportMeta: {
		Chrome:  {64},
		Edge:    {79},
		ES:      {2020},
		Firefox: {62},
		IOS:     {12},
		Node:    {10, 4},
		Safari:  {11, 1},
	},
	Let: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	LogicalAssignment: {
		Chrome:  {85},
		Edge:    {85},
		ES:      {2021},
		Firefox: {79},
		IOS:     {14},
		Node:    {15, 0},
		Safari:  {14},
	},
	NestedRestBinding: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2016},
		Firefox: {47},
		IOS:     {10, 3},
		Node:    {6},
		Safari:  {10, 1},
	},
	NewTarget: {
		Chrome:  {46},
		Edge:    {14},
		ES:      {2015},
		Firefox: {41},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	NullishCoalescing: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {72},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	ObjectAccessors: {
		Chrome:  {5},
		Edge:    {12},
		ES:      {5},
		Firefox: {2},
		IOS:     {6},
		Node:    {0, 10},
		Safari:  {3, 1},
	},
	ObjectExtensions: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {34},
		IOS:     {10},
		Node:    {4},
		Safari:  {10},
	},
	ObjectRestSpread: {
		ES:      {2018},
		Firefox: {55},
		IOS:     {11, 3},
		Safari:  {11, 1},
	},
	OptionalCatchBinding: {
		Chrome:  {66},
		Edge:    {79},
		ES:      {2019},
		Firefox: {58},
		IOS:     {11, 3},
		Node:    {10, 0},
		Safari:  {11, 1},
	},
	OptionalChain: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {74},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	RestArgument: {
		Chrome:  {47},
		Edge:    {12},
		ES:      {2015},
		Firefox: {43},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	TemplateLiteral: {
		Chrome:  {41},
		Edge:    {13},
		ES:      {2015},
		Firefox: {34},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
	TopLevelAwait: {
		Chrome: {89},
		Node:   {14, 8},
	},
	UnicodeEscapes: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {53},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
}

func isVersionLessThan(a []int, b []int) bool {
	for i := 0; i < len(a) && i < len(b); i++ {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}
	return len(a) < len(b)
}

// Return all features that are not available in at least one environment
func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) {
	for feature, engines := range jsTable {
		for engine, version := range constraints {
			if minVersion, ok := engines[engine]; !ok || isVersionLessThan(version, minVersion) {
				unsupported |= feature
			}
		}
	}
	return
}
<commit_msg>update browser compat data<commit_after>// This file was automatically generated by "compat-table.js"

package compat

type Engine uint8

const (
	Chrome Engine = iota
	Edge
	ES
	Firefox
	IOS
	Node
	Safari
)

func (e Engine) String() string {
	switch e {
	case Chrome:
		return "chrome"
	case Edge:
		return "edge"
	case ES:
		return "es"
	case Firefox:
		return "firefox"
	case IOS:
		return "ios"
	case Node:
		return "node"
	case Safari:
		return "safari"
	}
	return ""
}

type JSFeature uint64

const (
	ArbitraryModuleNamespaceNames JSFeature = 1 << iota
	ArraySpread
	Arrow
	AsyncAwait
	AsyncGenerator
	BigInt
	Class
	ClassField
	ClassPrivateAccessor
	ClassPrivateBrandCheck
	ClassPrivateField
	ClassPrivateMethod
	ClassPrivateStaticAccessor
	ClassPrivateStaticField
	ClassPrivateStaticMethod
	ClassStaticField
	Const
	DefaultArgument
	Destructuring
	DynamicImport
	ExponentOperator
	ExportStarAs
	ForAwait
	ForOf
	Generator
	Hashbang
	ImportAssertions
	ImportMeta
	Let
	LogicalAssignment
	NestedRestBinding
	NewTarget
	NullishCoalescing
	ObjectAccessors
	ObjectExtensions
	ObjectRestSpread
	OptionalCatchBinding
	OptionalChain
	RestArgument
	TemplateLiteral
	TopLevelAwait
	UnicodeEscapes
)

func (features JSFeature) Has(feature JSFeature) bool {
	return (features & feature) != 0
}

var jsTable = map[JSFeature]map[Engine][]int{
	ArbitraryModuleNamespaceNames: {
		Chrome: {90},
		Node:   {16},
	},
	ArraySpread: {
		Chrome:  {46},
		Edge:    {13},
		ES:      {2015},
		Firefox: {36},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	Arrow: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	AsyncAwait: {
		Chrome:  {55},
		Edge:    {15},
		ES:      {2017},
		Firefox: {52},
		IOS:     {11},
		Node:    {7, 6},
		Safari:  {11},
	},
	AsyncGenerator: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	BigInt: {
		Chrome:  {67},
		Edge:    {79},
		ES:      {2020},
		Firefox: {68},
		IOS:     {14},
		Node:    {10, 4},
		Safari:  {14},
	},
	Class: {
		Chrome:  {49},
		Edge:    {13},
		ES:      {2015},
		Firefox: {45},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	ClassField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {69},
		IOS:     {14},
		Node:    {12, 0},
		Safari:  {14},
	},
	ClassPrivateAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateBrandCheck: {
		Chrome:  {91},
		Firefox: {90},
		IOS:     {15},
		Safari:  {15},
	},
	ClassPrivateField: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {14, 1},
	},
	ClassPrivateMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateStaticAccessor: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassPrivateStaticField: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {90},
		IOS:     {15},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	ClassPrivateStaticMethod: {
		Chrome:  {84},
		Edge:    {84},
		Firefox: {90},
		IOS:     {15},
		Node:    {14, 6},
		Safari:  {15},
	},
	ClassStaticField: {
		Chrome:  {73},
		Edge:    {79},
		Firefox: {75},
		IOS:     {15},
		Node:    {12, 0},
		Safari:  {14, 1},
	},
	Const: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	DefaultArgument: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Destructuring: {
		Chrome:  {51},
		Edge:    {18},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	DynamicImport: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2015},
		Firefox: {67},
		IOS:     {11},
		Node:    {13, 2},
		Safari:  {11, 1},
	},
	ExponentOperator: {
		Chrome:  {52},
		Edge:    {14},
		ES:      {2016},
		Firefox: {52},
		IOS:     {10, 3},
		Node:    {7},
		Safari:  {10, 1},
	},
	ExportStarAs: {
		Chrome:  {72},
		Edge:    {79},
		ES:      {2020},
		Firefox: {80},
		Node:    {12},
	},
	ForAwait: {
		Chrome:  {63},
		Edge:    {79},
		ES:      {2018},
		Firefox: {57},
		IOS:     {12},
		Node:    {10, 0},
		Safari:  {12},
	},
	ForOf: {
		Chrome:  {51},
		Edge:    {15},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6, 5},
		Safari:  {10},
	},
	Generator: {
		Chrome:  {50},
		Edge:    {13},
		ES:      {2015},
		Firefox: {53},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	Hashbang: {
		Chrome:  {74},
		Edge:    {79},
		Firefox: {67},
		IOS:     {13, 4},
		Node:    {12, 0},
		Safari:  {13, 1},
	},
	ImportAssertions: {
		Chrome: {91},
	},
	ImportMeta: {
		Chrome:  {64},
		Edge:    {79},
		ES:      {2020},
		Firefox: {62},
		IOS:     {12},
		Node:    {10, 4},
		Safari:  {11, 1},
	},
	Let: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2015},
		Firefox: {51},
		IOS:     {11},
		Node:    {6},
		Safari:  {11},
	},
	LogicalAssignment: {
		Chrome:  {85},
		Edge:    {85},
		ES:      {2021},
		Firefox: {79},
		IOS:     {14},
		Node:    {15, 0},
		Safari:  {14},
	},
	NestedRestBinding: {
		Chrome:  {49},
		Edge:    {14},
		ES:      {2016},
		Firefox: {47},
		IOS:     {10, 3},
		Node:    {6},
		Safari:  {10, 1},
	},
	NewTarget: {
		Chrome:  {46},
		Edge:    {14},
		ES:      {2015},
		Firefox: {41},
		IOS:     {10},
		Node:    {5},
		Safari:  {10},
	},
	NullishCoalescing: {
		Chrome:  {80},
		Edge:    {80},
		ES:      {2020},
		Firefox: {72},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	ObjectAccessors: {
		Chrome:  {5},
		Edge:    {12},
		ES:      {5},
		Firefox: {2},
		IOS:     {6},
		Node:    {0, 10},
		Safari:  {3, 1},
	},
	ObjectExtensions: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {34},
		IOS:     {10},
		Node:    {4},
		Safari:  {10},
	},
	ObjectRestSpread: {
		ES:      {2018},
		Firefox: {55},
		IOS:     {11, 3},
		Safari:  {11, 1},
	},
	OptionalCatchBinding: {
		Chrome:  {66},
		Edge:    {79},
		ES:      {2019},
		Firefox: {58},
		IOS:     {11, 3},
		Node:    {10, 0},
		Safari:  {11, 1},
	},
	OptionalChain: {
		Chrome:  {91},
		Edge:    {80},
		ES:      {2020},
		Firefox: {74},
		IOS:     {13, 4},
		Node:    {14, 0},
		Safari:  {13, 1},
	},
	RestArgument: {
		Chrome:  {47},
		Edge:    {12},
		ES:      {2015},
		Firefox: {43},
		IOS:     {10},
		Node:    {6},
		Safari:  {10},
	},
	TemplateLiteral: {
		Chrome:  {41},
		Edge:    {13},
		ES:      {2015},
		Firefox: {34},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
	TopLevelAwait: {
		Chrome: {89},
		Node:   {14, 8},
	},
	UnicodeEscapes: {
		Chrome:  {44},
		Edge:    {12},
		ES:      {2015},
		Firefox: {53},
		IOS:     {9},
		Node:    {4},
		Safari:  {9},
	},
}

func isVersionLessThan(a []int, b []int) bool {
	for i := 0; i < len(a) && i < len(b); i++ {
		if a[i] > b[i] {
			return false
		}
		if a[i] < b[i] {
			return true
		}
	}
	return len(a) < len(b)
}

// Return all features that are not available in at least one environment
func UnsupportedJSFeatures(constraints map[Engine][]int) (unsupported JSFeature) {
	for feature, engines := range jsTable {
		for engine, version := range constraints {
			if minVersion, ok := engines[engine]; !ok || isVersionLessThan(version, minVersion) {
				unsupported |= feature
			}
		}
	}
	return
}
<|endoftext|>


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

package driver

type Modifier int

const (
	ModifierShift Modifier = 1 << iota
	ModifierControl
	ModifierAlt
	ModifierCapsLock
	ModifierNumLock
)
<commit_msg>internal/driver: remove an unused type Modifier<commit_after><|endoftext|>


<commit_before>package utils

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Rand", func() {
	It("generates random numbers", func() {
		const (
			num = 1000
			max = 123456
		)

		var values [num]int32
		var r Rand
		for i := 0; i < num; i++ {
			v := r.Int31n(max)
			Expect(v).To(And(
				BeNumerically(">=", 0),
				BeNumerically("<", max),
			))
			values[i] = v
		}

		var sum uint64
		for _, n := range values {
			sum += uint64(n)
		}
		Expect(float64(sum) / num).To(BeNumerically("~", max/2, max/25))
	})
})
<commit_msg>improve code coverage of random number generator test (#3358)<commit_after>package utils

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Rand", func() {
	It("generates random numbers", func() {
		const (
			num = 1000
			max = 12345678
		)

		var values [num]int32
		var r Rand
		for i := 0; i < num; i++ {
			v := r.Int31n(max)
			Expect(v).To(And(
				BeNumerically(">=", 0),
				BeNumerically("<", max),
			))
			values[i] = v
		}

		var sum uint64
		for _, n := range values {
			sum += uint64(n)
		}
		Expect(float64(sum) / num).To(BeNumerically("~", max/2, max/25))
	})
})
<|endoftext|>