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

package cmd

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

	"github.com/aquasecurity/kube-bench/check"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	errmsgs string
)

func runChecks(nodetype check.NodeType) {
	var summary check.Summary

	def := loadConfig(nodetype)
	in, err := ioutil.ReadFile(def)
	if err != nil {
		exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
	}

	glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))

	// Get the set of exectuables and config files we care about on this type of node.
	typeConf := viper.Sub(string(nodetype))
	binmap, err := getBinaries(typeConf)

	// Checks that the executables we need for the node type are running.
	if err != nil {
		exitWithError(err)
	}

	confmap := getConfigFiles(typeConf)
	svcmap := getServiceFiles(typeConf)
	kubeconfmap := getKubeConfigFiles(typeConf)

	// Variable substitutions. Replace all occurrences of variables in controls files.
	s := string(in)
	s = makeSubstitutions(s, "bin", binmap)
	s = makeSubstitutions(s, "conf", confmap)
	s = makeSubstitutions(s, "svc", svcmap)
	s = makeSubstitutions(s, "kubeconfig", kubeconfmap)

	controls, err := check.NewControls(nodetype, []byte(s))
	if err != nil {
		exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
	}

	if groupList != "" && checkList == "" {
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)
	} else if checkList != "" && groupList == "" {
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)
	} else if checkList != "" && groupList != "" {
		exitWithError(fmt.Errorf("group option and check option can't be used together"))
	} else {
		summary = controls.RunGroup()
	}

	// if we successfully ran some tests and it's json format, ignore the warnings
	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
		}

		fmt.Println(string(out))
	} else {
		// if we want to store in PostgreSQL, convert to JSON and save it
		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
			out, err := controls.JSON()
			if err != nil {
				exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
			}

			savePgsql(string(out))
		} else {
			prettyPrint(controls, summary)
		}
	}
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

// prettyPrint outputs the results to stdout in human-readable format
func prettyPrint(r *check.Controls, summary check.Summary) {
	// Print check results.
	if !noResults {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
		for _, g := range r.Groups {
			colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
			for _, c := range g.Checks {
				colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
			}
		}

		fmt.Println()
	}

	// Print remediations.
	if !noRemediations {
		if summary.Fail > 0 || summary.Warn > 0 {
			colors[check.WARN].Printf("== Remediations ==\n")
			for _, g := range r.Groups {
				for _, c := range g.Checks {
					if c.State == check.FAIL || c.State == check.WARN {
						fmt.Printf("%s %s\n", c.ID, c.Remediation)
					}
				}
			}
			fmt.Println()
		}
	}

	// Print summary setting output color to highest severity.
	if !noSummary {
		var res check.State
		if summary.Fail > 0 {
			res = check.FAIL
		} else if summary.Warn > 0 {
			res = check.WARN
		} else {
			res = check.PASS
		}

		colors[res].Printf("== Summary ==\n")
		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
			summary.Pass, summary.Fail, summary.Warn, summary.Info,
		)
	}
}

// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
func loadConfig(nodetype check.NodeType) string {
	var file string
	var err error

	switch nodetype {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	runningVersion := ""
	if kubeVersion == "" {
		runningVersion, err = getKubeVersion()
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
		}
	}
	path, err := getConfigFilePath(kubeVersion, runningVersion, file)
	if err != nil {
		exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
	}

	// Merge kubernetes version specific config if any.
	viper.SetConfigFile(path + "/config.yaml")
	err = viper.MergeInConfig()
	if err != nil {
		if os.IsNotExist(err) {
			glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
		} else {
			exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
		}
	} else {
		glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
	}
	return filepath.Join(path, file)
}

// isMaster verify if master components are running on the node.
func isMaster() bool {
	_ = loadConfig(check.MASTER)
	glog.V(2).Info("Checking if the current node is running master components")
	masterConf := viper.Sub(string(check.MASTER))
	if _, err := getBinaries(masterConf); err != nil {
		glog.V(2).Info(err)
		return false
	}
	return true
}
<commit_msg>Don't assume master if 0 master binaries specified<commit_after>// Copyright © 2017 Aqua Security Software Ltd. <info@aquasec.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

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

	"github.com/aquasecurity/kube-bench/check"
	"github.com/golang/glog"
	"github.com/spf13/viper"
)

var (
	errmsgs string
)

func runChecks(nodetype check.NodeType) {
	var summary check.Summary

	def := loadConfig(nodetype)
	in, err := ioutil.ReadFile(def)
	if err != nil {
		exitWithError(fmt.Errorf("error opening %s controls file: %v", nodetype, err))
	}

	glog.V(1).Info(fmt.Sprintf("Using benchmark file: %s\n", def))

	// Get the set of exectuables and config files we care about on this type of node.
	typeConf := viper.Sub(string(nodetype))
	binmap, err := getBinaries(typeConf)

	// Checks that the executables we need for the node type are running.
	if err != nil {
		exitWithError(err)
	}

	confmap := getConfigFiles(typeConf)
	svcmap := getServiceFiles(typeConf)
	kubeconfmap := getKubeConfigFiles(typeConf)

	// Variable substitutions. Replace all occurrences of variables in controls files.
	s := string(in)
	s = makeSubstitutions(s, "bin", binmap)
	s = makeSubstitutions(s, "conf", confmap)
	s = makeSubstitutions(s, "svc", svcmap)
	s = makeSubstitutions(s, "kubeconfig", kubeconfmap)

	controls, err := check.NewControls(nodetype, []byte(s))
	if err != nil {
		exitWithError(fmt.Errorf("error setting up %s controls: %v", nodetype, err))
	}

	if groupList != "" && checkList == "" {
		ids := cleanIDs(groupList)
		summary = controls.RunGroup(ids...)
	} else if checkList != "" && groupList == "" {
		ids := cleanIDs(checkList)
		summary = controls.RunChecks(ids...)
	} else if checkList != "" && groupList != "" {
		exitWithError(fmt.Errorf("group option and check option can't be used together"))
	} else {
		summary = controls.RunGroup()
	}

	// if we successfully ran some tests and it's json format, ignore the warnings
	if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && jsonFmt {
		out, err := controls.JSON()
		if err != nil {
			exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
		}

		fmt.Println(string(out))
	} else {
		// if we want to store in PostgreSQL, convert to JSON and save it
		if (summary.Fail > 0 || summary.Warn > 0 || summary.Pass > 0 || summary.Info > 0) && pgSQL {
			out, err := controls.JSON()
			if err != nil {
				exitWithError(fmt.Errorf("failed to output in JSON format: %v", err))
			}

			savePgsql(string(out))
		} else {
			prettyPrint(controls, summary)
		}
	}
}

// colorPrint outputs the state in a specific colour, along with a message string
func colorPrint(state check.State, s string) {
	colors[state].Printf("[%s] ", state)
	fmt.Printf("%s", s)
}

// prettyPrint outputs the results to stdout in human-readable format
func prettyPrint(r *check.Controls, summary check.Summary) {
	// Print check results.
	if !noResults {
		colorPrint(check.INFO, fmt.Sprintf("%s %s\n", r.ID, r.Text))
		for _, g := range r.Groups {
			colorPrint(check.INFO, fmt.Sprintf("%s %s\n", g.ID, g.Text))
			for _, c := range g.Checks {
				colorPrint(c.State, fmt.Sprintf("%s %s\n", c.ID, c.Text))
			}
		}

		fmt.Println()
	}

	// Print remediations.
	if !noRemediations {
		if summary.Fail > 0 || summary.Warn > 0 {
			colors[check.WARN].Printf("== Remediations ==\n")
			for _, g := range r.Groups {
				for _, c := range g.Checks {
					if c.State == check.FAIL || c.State == check.WARN {
						fmt.Printf("%s %s\n", c.ID, c.Remediation)
					}
				}
			}
			fmt.Println()
		}
	}

	// Print summary setting output color to highest severity.
	if !noSummary {
		var res check.State
		if summary.Fail > 0 {
			res = check.FAIL
		} else if summary.Warn > 0 {
			res = check.WARN
		} else {
			res = check.PASS
		}

		colors[res].Printf("== Summary ==\n")
		fmt.Printf("%d checks PASS\n%d checks FAIL\n%d checks WARN\n%d checks INFO\n",
			summary.Pass, summary.Fail, summary.Warn, summary.Info,
		)
	}
}

// loadConfig finds the correct config dir based on the kubernetes version,
// merges any specific config.yaml file found with the main config
// and returns the benchmark file to use.
func loadConfig(nodetype check.NodeType) string {
	var file string
	var err error

	switch nodetype {
	case check.MASTER:
		file = masterFile
	case check.NODE:
		file = nodeFile
	case check.FEDERATED:
		file = federatedFile
	}

	runningVersion := ""
	if kubeVersion == "" {
		runningVersion, err = getKubeVersion()
		if err != nil {
			exitWithError(fmt.Errorf("Version check failed: %s\nAlternatively, you can specify the version with --version", err))
		}
	}
	path, err := getConfigFilePath(kubeVersion, runningVersion, file)
	if err != nil {
		exitWithError(fmt.Errorf("can't find %s controls file in %s: %v", nodetype, cfgDir, err))
	}

	// Merge kubernetes version specific config if any.
	viper.SetConfigFile(path + "/config.yaml")
	err = viper.MergeInConfig()
	if err != nil {
		if os.IsNotExist(err) {
			glog.V(2).Info(fmt.Sprintf("No version-specific config.yaml file in %s", path))
		} else {
			exitWithError(fmt.Errorf("couldn't read config file %s: %v", path+"/config.yaml", err))
		}
	} else {
		glog.V(1).Info(fmt.Sprintf("Using config file: %s\n", viper.ConfigFileUsed()))
	}
	return filepath.Join(path, file)
}

// isMaster verify if master components are running on the node.
func isMaster() bool {
	_ = loadConfig(check.MASTER)
	glog.V(2).Info("Checking if the current node is running master components")
	masterConf := viper.Sub(string(check.MASTER))
	components, err := getBinaries(masterConf)

	if err != nil {
		glog.V(2).Info(err)
		return false
	}
	if len(components) == 0 {
		glog.V(2).Info("No master binaries specified")
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package cmd

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/alexzorin/onapp"
	"github.com/alexzorin/onapp/cmd/log"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"reflect"
	"strings"
)

const (
	configCmdDescription = "Configure this tool"
	configCmdHelp        = "This command is an interactive wizard to help you setup this tool.\n" +
		"You will need your OnApp dashboard URL, email address and API key to complete it."
)

type config struct {
	ConfigFile string
	ApiUser    string
	ApiKey     string
	Server     string
	Verbose    bool
}

type configCmd struct {
}

func (c configCmd) Run(args []string, ctx *cli) error {

	log.Infoln("This is the configuration wizard. Please provide the following: \n")
	reader := bufio.NewReader(os.Stdin)

	log.Infof("Hostname of the OnApp dashboard: ")
	host, err := reader.ReadString('\n')
	if err != nil {
		return err
	}
	log.Infof("API Username (generally the email address): ")
	user, err := reader.ReadString('\n')
	if err != nil {
		return err
	}
	log.Infof("API Key: ")
	apiKey, err := reader.ReadString('\n')
	if err != nil {
		return err
	}

	log.Infof("Test these details? [y/n]: ")
	doTest, err := reader.ReadString('\n')
	if err != nil {
		return err
	}

	ctx.config.Server = strings.Trim(host, "\r\n")
	ctx.config.ApiUser = strings.Trim(user, "\r\n")
	ctx.config.ApiKey = strings.Trim(apiKey, "\r\n")

	if strings.ToLower(doTest)[0] == 'y' {
		err := c.testCredentials(ctx.config.Server, ctx.config.ApiUser, ctx.config.ApiKey)
		if err != nil {
			return err
		}
	}

	_, err = os.Stat(ctx.config.ConfigFile)
	if err == nil {
		log.Infof("Config file already exists at '%s', overwrite? [y/n]: ", ctx.config.ConfigFile)
		cont, err := reader.ReadString('\n')
		if err != nil || strings.ToLower(cont)[0] != 'y' {
			return errors.New("User aborted saving configuration")
		}
	}

	err = ctx.config.save()
	if err != nil {
		log.Errorln(err)
	} else {
		log.Successln("\nSaved configuration to", ctx.config.ConfigFile)
	}

	return nil
}

func (c configCmd) testCredentials(host string, user string, pass string) error {
	client, err := onapp.NewClient(host, user, pass)
	if err != nil {
		return err
	}
	_, err = client.GetProfile()
	if err != nil {
		return err
	}
	return nil
}

func (c configCmd) Description() string {
	return configCmdDescription
}

func (c configCmd) Help(args []string) {
	log.Infoln(configCmdHelp)
}

func (c *config) save() error {
	data, err := json.Marshal(c)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(c.ConfigFile, data, 0644)
	if err != nil {
		return err
	}
	return nil
}

func loadConfig() (*config, error) {
	conf := &config{}

	u, err := user.Current()
	if err != nil {
		return conf, err
	}

	flag.StringVar(&conf.ConfigFile, "configFile", fmt.Sprintf("%s%c.onapp", u.HomeDir, os.PathSeparator), "Path to config file")
	flag.BoolVar(&conf.Verbose, "v", false, "Verbose logging")
	flag.Parse()

	_, err = os.Stat(conf.ConfigFile)
	var merge *config
	if err != nil {
		merge = &config{}
	} else {
		rawConf, err := ioutil.ReadFile(conf.ConfigFile)
		if err != nil {
			return conf, errors.New(fmt.Sprintf("Error reading from %s: %s", conf.ConfigFile, err.Error()))
		}
		confFromFile := &config{}
		err = json.Unmarshal(rawConf, confFromFile)
		if err != nil {
			return conf, errors.New(fmt.Sprintf("Error parsing %s: %s", conf.ConfigFile, err.Error()))
		}
		merge = confFromFile
	}
	merged, err := mergeConfigs(conf, merge)
	if err != nil {
		return conf, err
	}

	if merged.ApiUser == "" || merged.ApiKey == "" || merged.Server == "" {
		log.Warnf("You haven't configured yet. Try `%s config`.\n", filepath.Base(os.Args[0]))
	}

	return merged, nil
}

/* Single depth merging, prefers values in `first` over `second` */
func mergeConfigs(first *config, second *config) (*config, error) {
	merged := &config{}
	r1 := reflect.ValueOf(*first)
	r2 := reflect.ValueOf(*second)
	for i := 0; i < r1.NumField(); i++ {
		f1 := r1.Field(i)
		f2 := r2.Field(i)
		dst := reflect.ValueOf(merged).Elem().Field(i)
		switch f1.Kind() {
		case reflect.String:
			if f1.String() == "" {
				dst.SetString(f2.String())
			} else {
				dst.SetString(f1.String())
			}
		case reflect.Bool:
			if f1.Bool() || f2.Bool() {
				dst.SetBool(true)
			}
		}
	}
	return merged, nil
}
<commit_msg>remove verbose flag unused<commit_after>package cmd

import (
	"bufio"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"github.com/alexzorin/onapp"
	"github.com/alexzorin/onapp/cmd/log"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"reflect"
	"strings"
)

const (
	configCmdDescription = "Configure this tool"
	configCmdHelp        = "This command is an interactive wizard to help you setup this tool.\n" +
		"You will need your OnApp dashboard URL, email address and API key to complete it."
)

type config struct {
	ConfigFile string
	ApiUser    string
	ApiKey     string
	Server     string
}

type configCmd struct {
}

func (c configCmd) Run(args []string, ctx *cli) error {

	log.Infoln("This is the configuration wizard. Please provide the following: \n")
	reader := bufio.NewReader(os.Stdin)

	log.Infof("Hostname of the OnApp dashboard: ")
	host, err := reader.ReadString('\n')
	if err != nil {
		return err
	}
	log.Infof("API Username (generally the email address): ")
	user, err := reader.ReadString('\n')
	if err != nil {
		return err
	}
	log.Infof("API Key: ")
	apiKey, err := reader.ReadString('\n')
	if err != nil {
		return err
	}

	log.Infof("Test these details? [y/n]: ")
	doTest, err := reader.ReadString('\n')
	if err != nil {
		return err
	}

	ctx.config.Server = strings.Trim(host, "\r\n")
	ctx.config.ApiUser = strings.Trim(user, "\r\n")
	ctx.config.ApiKey = strings.Trim(apiKey, "\r\n")

	if strings.ToLower(doTest)[0] == 'y' {
		err := c.testCredentials(ctx.config.Server, ctx.config.ApiUser, ctx.config.ApiKey)
		if err != nil {
			return err
		}
	}

	_, err = os.Stat(ctx.config.ConfigFile)
	if err == nil {
		log.Infof("Config file already exists at '%s', overwrite? [y/n]: ", ctx.config.ConfigFile)
		cont, err := reader.ReadString('\n')
		if err != nil || strings.ToLower(cont)[0] != 'y' {
			return errors.New("User aborted saving configuration")
		}
	}

	err = ctx.config.save()
	if err != nil {
		log.Errorln(err)
	} else {
		log.Successln("\nSaved configuration to", ctx.config.ConfigFile)
	}

	return nil
}

func (c configCmd) testCredentials(host string, user string, pass string) error {
	client, err := onapp.NewClient(host, user, pass)
	if err != nil {
		return err
	}
	_, err = client.GetProfile()
	if err != nil {
		return err
	}
	return nil
}

func (c configCmd) Description() string {
	return configCmdDescription
}

func (c configCmd) Help(args []string) {
	log.Infoln(configCmdHelp)
}

func (c *config) save() error {
	data, err := json.Marshal(c)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(c.ConfigFile, data, 0644)
	if err != nil {
		return err
	}
	return nil
}

func loadConfig() (*config, error) {
	conf := &config{}

	u, err := user.Current()
	if err != nil {
		return conf, err
	}

	flag.StringVar(&conf.ConfigFile, "configFile", fmt.Sprintf("%s%c.onapp", u.HomeDir, os.PathSeparator), "Path to config file")
	flag.Parse()

	_, err = os.Stat(conf.ConfigFile)
	var merge *config
	if err != nil {
		merge = &config{}
	} else {
		rawConf, err := ioutil.ReadFile(conf.ConfigFile)
		if err != nil {
			return conf, errors.New(fmt.Sprintf("Error reading from %s: %s", conf.ConfigFile, err.Error()))
		}
		confFromFile := &config{}
		err = json.Unmarshal(rawConf, confFromFile)
		if err != nil {
			return conf, errors.New(fmt.Sprintf("Error parsing %s: %s", conf.ConfigFile, err.Error()))
		}
		merge = confFromFile
	}
	merged, err := mergeConfigs(conf, merge)
	if err != nil {
		return conf, err
	}

	if merged.ApiUser == "" || merged.ApiKey == "" || merged.Server == "" {
		log.Warnf("You haven't configured yet. Try `%s config`.\n", filepath.Base(os.Args[0]))
	}

	return merged, nil
}

/* Single depth merging, prefers values in `first` over `second` */
func mergeConfigs(first *config, second *config) (*config, error) {
	merged := &config{}
	r1 := reflect.ValueOf(*first)
	r2 := reflect.ValueOf(*second)
	for i := 0; i < r1.NumField(); i++ {
		f1 := r1.Field(i)
		f2 := r2.Field(i)
		dst := reflect.ValueOf(merged).Elem().Field(i)
		switch f1.Kind() {
		case reflect.String:
			if f1.String() == "" {
				dst.SetString(f2.String())
			} else {
				dst.SetString(f1.String())
			}
		case reflect.Bool:
			if f1.Bool() || f2.Bool() {
				dst.SetBool(true)
			}
		}
	}
	return merged, nil
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/api/infoGatherer"
	"github.com/getgauge/gauge/api/lang"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/track"
	"github.com/spf13/cobra"
)

var (
	daemonCmd = &cobra.Command{
		Use:     "daemon [flags] <port> [args]",
		Short:   "Run as a daemon",
		Long:    `Run as a daemon.`,
		Example: "  gauge daemon 1234",
		Run: func(cmd *cobra.Command, args []string) {
			if err := config.SetProjectRoot(args); err != nil {
				logger.Fatalf(err.Error())
			}
			if lsp {
				track.Lsp()
				lang.Server(&infoGatherer.SpecInfoGatherer{SpecDirs: getSpecsDir(args)}).Start()
				return
			}
			track.Daemon()
			port := ""
			specs := args
			if len(args) > 0 {
				port = args[0]
				specs = getSpecsDir(args[1:])
			}
			api.RunInBackground(port, specs)
		},
		DisableAutoGenTag: true,
	}
	lsp bool
)

func init() {
	GaugeCmd.AddCommand(daemonCmd)
	daemonCmd.Flags().BoolVarP(&lsp, "lsp", "", false, "Start language server")
	daemonCmd.Flags().MarkHidden("lsp")
}
<commit_msg>set default specs directory='specs' in daemon<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"github.com/getgauge/common"
	"github.com/getgauge/gauge/api"
	"github.com/getgauge/gauge/api/infoGatherer"
	"github.com/getgauge/gauge/api/lang"
	"github.com/getgauge/gauge/config"
	"github.com/getgauge/gauge/logger"
	"github.com/getgauge/gauge/track"
	"github.com/spf13/cobra"
)

var (
	daemonCmd = &cobra.Command{
		Use:     "daemon [flags] <port> [args]",
		Short:   "Run as a daemon",
		Long:    `Run as a daemon.`,
		Example: "  gauge daemon 1234",
		Run: func(cmd *cobra.Command, args []string) {
			if err := config.SetProjectRoot(args); err != nil {
				logger.Fatalf(err.Error())
			}
			if lsp {
				track.Lsp()
				lang.Server(&infoGatherer.SpecInfoGatherer{SpecDirs: getSpecsDir(args)}).Start()
				return
			}
			track.Daemon()
			port := ""
			specs := []string{common.SpecsDirectoryName}
			if len(args) > 0 {
				port = args[0]
				specs = getSpecsDir(args[1:])
			}
			api.RunInBackground(port, specs)
		},
		DisableAutoGenTag: true,
	}
	lsp bool
)

func init() {
	GaugeCmd.AddCommand(daemonCmd)
	daemonCmd.Flags().BoolVarP(&lsp, "lsp", "", false, "Start language server")
	daemonCmd.Flags().MarkHidden("lsp")
}
<|endoftext|>


<commit_before>package proxy

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	sbAudio "github.com/dh1tw/remoteAudio/sb_audio"
	"github.com/gogo/protobuf/proto"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/client"
)

type AudioServer struct {
	sync.RWMutex
	name           string
	serviceName    string
	client         client.Client
	rpc            sbAudio.ServerService
	stateSub       broker.Subscriber
	rxAddress      string
	txAddress      string
	stateAddress   string
	rxOn           bool
	txUser         string
	latency        int
	notifyChangeCb func()
	closePing      chan struct{}
	doneCh         chan struct{}
	doneOnce       sync.Once
}

func NewAudioServer(name string, client client.Client, doneCh chan struct{}, opts ...Option) (*AudioServer, error) {

	serviceName := fmt.Sprintf("shackbus.radio.%s.audio", name)

	as := &AudioServer{
		name:         name,
		serviceName:  serviceName,
		client:       client,
		rxAddress:    fmt.Sprintf("%s.rx", serviceName),
		txAddress:    fmt.Sprintf("%s.tx", serviceName),
		stateAddress: fmt.Sprintf("%s.state", serviceName),
		txUser:       "",
		closePing:    make(chan struct{}),
		doneCh:       doneCh,
	}

	as.rpc = sbAudio.NewServerService(as.serviceName, as.client)

	if err := as.getCapabilities(); err != nil {
		return nil, err
	}
	if err := as.getState(); err != nil {
		return nil, err
	}

	sub, err := as.client.Options().Broker.Subscribe(as.stateAddress, as.stateUpdateCb)
	if err != nil {
		return nil, err
	}

	as.stateSub = sub

	// start a go routine to ping our service every second
	go func() {
		for {
			select {
			case <-time.After(time.Second * 3):

				ping, err := as.ping()

				if err != nil {
					log.Println("unable to ping service", as.Name())
					as.closeDone()
					return
				}
				as.Lock()
				as.latency = ping
				as.Unlock()
				go as.notifyChangeCb()
			case <-as.closePing:
				return
			}
		}
	}()

	return as, nil
}

// the doneCh must be closed through this function to avoid
// multiple times closing this channel. Closing the doneCh signals the
// application that this object can be disposed.
func (as *AudioServer) closeDone() {
	as.doneOnce.Do(func() { close(as.doneCh) })
}

// Close shutsdown this object and all associated go routines so that
// it can be garbage collected.
func (as *AudioServer) Close() {
	as.Lock()
	defer as.Unlock()

	as.stateSub.Unsubscribe()
	close(as.closePing)
	as.rpc = nil
	as.client = nil
	as.notifyChangeCb = nil
	as.closeDone()
}

// ping performs a ping request to the audio server and returns the
// oneway latency (ping/2) in milli seconds.
func (as *AudioServer) ping() (int, error) {

	ping := time.Now().UnixNano() / int64(time.Millisecond)

	pingMsg := sbAudio.PingPong{
		Ping: ping,
	}

	pong, err := as.rpc.Ping(context.Background(), &pingMsg)
	if err != nil {
		return 0, err
	}

	now := time.Now().UnixNano() / int64(time.Millisecond)

	res := int((now - pong.Ping) / 2)
	return res, nil
}

func (as *AudioServer) SetNotifyCb(f func()) {
	as.Lock()
	defer as.Unlock()
	as.notifyChangeCb = f
}

func (as *AudioServer) Name() string {
	as.RLock()
	defer as.RUnlock()
	return as.name
}

func (as *AudioServer) ServiceName() string {
	as.RLock()
	defer as.RUnlock()
	return as.serviceName
}

func (as *AudioServer) RxOn() bool {
	as.RLock()
	defer as.RUnlock()
	return as.rxOn
}

func (as *AudioServer) RxAddress() string {
	as.RLock()
	defer as.RUnlock()
	return as.rxAddress
}

func (as *AudioServer) TxAddress() string {
	as.RLock()
	defer as.RUnlock()
	return as.txAddress
}

func (as *AudioServer) StartRxStream() error {
	_, err := as.rpc.StartStream(context.Background(), &sbAudio.None{})
	if err != nil {
		return err
	}
	as.Lock()
	as.rxOn = true
	as.Unlock()
	return nil
}

func (as *AudioServer) StopRxStream() error {
	_, err := as.rpc.StopStream(context.Background(), &sbAudio.None{})
	if err != nil {
		return err
	}
	as.Lock()
	as.rxOn = false
	as.Unlock()
	return nil
}

func (as *AudioServer) TxUser() string {
	as.RLock()
	defer as.RUnlock()
	return as.txUser
}

func (as *AudioServer) Latency() int {
	as.RLock()
	defer as.RUnlock()
	return as.latency
}

func (as *AudioServer) stateUpdateCb(msg broker.Publication) error {

	newState := sbAudio.State{}

	if err := proto.Unmarshal(msg.Message().Body, &newState); err != nil {
		return err
	}
	as.Lock()
	defer as.Unlock()

	as.rxOn = newState.GetRxOn()
	as.txUser = newState.GetTxUser()

	if as.notifyChangeCb != nil {
		go as.notifyChangeCb()
	}

	// TBD check if something has changed and notify subcribers

	return nil
}

func (as *AudioServer) getState() error {
	state, err := as.rpc.GetState(context.Background(), &sbAudio.None{})
	if err != nil {
		return fmt.Errorf("getState: %v", err)
	}
	as.Lock()
	defer as.Unlock()
	as.rxOn = state.RxOn
	as.txUser = state.TxUser

	return nil
}

func (as *AudioServer) getCapabilities() error {
	caps, err := as.rpc.GetCapabilities(context.Background(), &sbAudio.None{})
	if err != nil {
		return fmt.Errorf("getCapabilities: %v", err)
	}
	as.Lock()
	defer as.Unlock()
	as.rxAddress = caps.GetRxStreamAddress()
	if len(as.rxAddress) == 0 {
		return fmt.Errorf("getCapabilities: RxStreamAddress empty")
	}
	as.txAddress = caps.GetTxStreamAddress()
	if len(as.txAddress) == 0 {
		return fmt.Errorf("getCapabilities: TxStreamAddress empty")
	}
	as.stateAddress = caps.GetStateUpdatesAddress()
	if len(as.stateAddress) == 0 {
		return fmt.Errorf("getCapabilities: StateUpdatesAddress empty")
	}
	return nil
}
<commit_msg>changed latency to ping time (2-way)<commit_after>package proxy

import (
	"context"
	"fmt"
	"log"
	"sync"
	"time"

	sbAudio "github.com/dh1tw/remoteAudio/sb_audio"
	"github.com/gogo/protobuf/proto"
	"github.com/micro/go-micro/broker"
	"github.com/micro/go-micro/client"
)

type AudioServer struct {
	sync.RWMutex
	name           string
	serviceName    string
	client         client.Client
	rpc            sbAudio.ServerService
	stateSub       broker.Subscriber
	rxAddress      string
	txAddress      string
	stateAddress   string
	rxOn           bool
	txUser         string
	latency        int
	notifyChangeCb func()
	closePing      chan struct{}
	doneCh         chan struct{}
	doneOnce       sync.Once
}

func NewAudioServer(name string, client client.Client, doneCh chan struct{}, opts ...Option) (*AudioServer, error) {

	serviceName := fmt.Sprintf("shackbus.radio.%s.audio", name)

	as := &AudioServer{
		name:         name,
		serviceName:  serviceName,
		client:       client,
		rxAddress:    fmt.Sprintf("%s.rx", serviceName),
		txAddress:    fmt.Sprintf("%s.tx", serviceName),
		stateAddress: fmt.Sprintf("%s.state", serviceName),
		txUser:       "",
		closePing:    make(chan struct{}),
		doneCh:       doneCh,
	}

	as.rpc = sbAudio.NewServerService(as.serviceName, as.client)

	if err := as.getCapabilities(); err != nil {
		return nil, err
	}
	if err := as.getState(); err != nil {
		return nil, err
	}

	sub, err := as.client.Options().Broker.Subscribe(as.stateAddress, as.stateUpdateCb)
	if err != nil {
		return nil, err
	}

	as.stateSub = sub

	// start a go routine to ping our service every second
	go func() {
		for {
			select {
			case <-time.After(time.Second * 3):

				ping, err := as.ping()

				if err != nil {
					log.Println("unable to ping service", as.Name())
					as.closeDone()
					return
				}
				as.Lock()
				as.latency = ping
				as.Unlock()
				go as.notifyChangeCb()
			case <-as.closePing:
				return
			}
		}
	}()

	return as, nil
}

// the doneCh must be closed through this function to avoid
// multiple times closing this channel. Closing the doneCh signals the
// application that this object can be disposed.
func (as *AudioServer) closeDone() {
	as.doneOnce.Do(func() { close(as.doneCh) })
}

// Close shutsdown this object and all associated go routines so that
// it can be garbage collected.
func (as *AudioServer) Close() {
	as.Lock()
	defer as.Unlock()

	as.stateSub.Unsubscribe()
	close(as.closePing)
	as.rpc = nil
	as.client = nil
	as.notifyChangeCb = nil
	as.closeDone()
}

// ping performs a ping request to the audio server and returns the
// latency (ping / 2-way) in milliseconds.
func (as *AudioServer) ping() (int, error) {

	ping := time.Now().UnixNano() / int64(time.Millisecond)

	pingMsg := sbAudio.PingPong{
		Ping: ping,
	}

	pong, err := as.rpc.Ping(context.Background(), &pingMsg)
	if err != nil {
		return 0, err
	}

	now := time.Now().UnixNano() / int64(time.Millisecond)

	res := int(now - pong.Ping)
	return res, nil
}

func (as *AudioServer) SetNotifyCb(f func()) {
	as.Lock()
	defer as.Unlock()
	as.notifyChangeCb = f
}

func (as *AudioServer) Name() string {
	as.RLock()
	defer as.RUnlock()
	return as.name
}

func (as *AudioServer) ServiceName() string {
	as.RLock()
	defer as.RUnlock()
	return as.serviceName
}

func (as *AudioServer) RxOn() bool {
	as.RLock()
	defer as.RUnlock()
	return as.rxOn
}

func (as *AudioServer) RxAddress() string {
	as.RLock()
	defer as.RUnlock()
	return as.rxAddress
}

func (as *AudioServer) TxAddress() string {
	as.RLock()
	defer as.RUnlock()
	return as.txAddress
}

func (as *AudioServer) StartRxStream() error {
	_, err := as.rpc.StartStream(context.Background(), &sbAudio.None{})
	if err != nil {
		return err
	}
	as.Lock()
	as.rxOn = true
	as.Unlock()
	return nil
}

func (as *AudioServer) StopRxStream() error {
	_, err := as.rpc.StopStream(context.Background(), &sbAudio.None{})
	if err != nil {
		return err
	}
	as.Lock()
	as.rxOn = false
	as.Unlock()
	return nil
}

func (as *AudioServer) TxUser() string {
	as.RLock()
	defer as.RUnlock()
	return as.txUser
}

func (as *AudioServer) Latency() int {
	as.RLock()
	defer as.RUnlock()
	return as.latency
}

func (as *AudioServer) stateUpdateCb(msg broker.Publication) error {

	newState := sbAudio.State{}

	if err := proto.Unmarshal(msg.Message().Body, &newState); err != nil {
		return err
	}
	as.Lock()
	defer as.Unlock()

	as.rxOn = newState.GetRxOn()
	as.txUser = newState.GetTxUser()

	if as.notifyChangeCb != nil {
		go as.notifyChangeCb()
	}

	// TBD check if something has changed and notify subcribers

	return nil
}

func (as *AudioServer) getState() error {
	state, err := as.rpc.GetState(context.Background(), &sbAudio.None{})
	if err != nil {
		return fmt.Errorf("getState: %v", err)
	}
	as.Lock()
	defer as.Unlock()
	as.rxOn = state.RxOn
	as.txUser = state.TxUser

	return nil
}

func (as *AudioServer) getCapabilities() error {
	caps, err := as.rpc.GetCapabilities(context.Background(), &sbAudio.None{})
	if err != nil {
		return fmt.Errorf("getCapabilities: %v", err)
	}
	as.Lock()
	defer as.Unlock()
	as.rxAddress = caps.GetRxStreamAddress()
	if len(as.rxAddress) == 0 {
		return fmt.Errorf("getCapabilities: RxStreamAddress empty")
	}
	as.txAddress = caps.GetTxStreamAddress()
	if len(as.txAddress) == 0 {
		return fmt.Errorf("getCapabilities: TxStreamAddress empty")
	}
	as.stateAddress = caps.GetStateUpdatesAddress()
	if len(as.stateAddress) == 0 {
		return fmt.Errorf("getCapabilities: StateUpdatesAddress empty")
	}
	return nil
}
<|endoftext|>


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

package query

import (
	"errors"
	"fmt"

	"github.com/square/metrics/api"
)

// EvaluationContext is the central piece of logic, providing
// helper funcions & varaibles to evaluate a given piece of
// metrics query.
// * Contains Backend object, which can be used to fetch data
// from the backend system.s
// * Contains current timerange being queried for - this can be
// changed by say, application of time shift function.
type EvaluationContext struct {
	// Backend to fetch data from
	Backend api.Backend
	// Timerange to fetch data from
	Timerange api.Timerange
	// SampleMethod to use when up/downsampling to match the requested resolution
	SampleMethod api.SampleMethod
	Predicate    api.Predicate
}

// A value is the result of evaluating an expression.
// They can be floating point values, strings, or series lists.
type value interface {
	toSeriesList(api.Timerange) (api.SeriesList, error)
	toString() (string, error)
	toScalar() (float64, error)
}

type conversionError struct {
	from string
	to   string
}

func (e conversionError) Error() string {
	return fmt.Sprintf("cannot convert from type %s to type %s", e.from, e.to)
}

// A seriesListValue is a value which holds a SeriesList
type seriesListValue api.SeriesList

func (value seriesListValue) toSeriesList(time api.Timerange) (api.SeriesList, error) {
	return api.SeriesList(value), nil
}
func (value seriesListValue) toString() (string, error) {
	return "", conversionError{"SeriesList", "string"}
}
func (value seriesListValue) toScalar() (float64, error) {
	return 0, conversionError{"SeriesList", "scalar"}
}

// A stringValue holds a string
type stringValue string

func (value stringValue) toSeriesList(time api.Timerange) (api.SeriesList, error) {
	return api.SeriesList{}, conversionError{"string", "SeriesList"}
}
func (value stringValue) toString() (string, error) {
	return string(value), nil
}
func (value stringValue) toScalar() (float64, error) {
	return 0, conversionError{"string", "scalar"}
}

// A scalarValue holds a float and can be converted to a serieslist
type scalarValue float64

func (value scalarValue) toSeriesList(timerange api.Timerange) (api.SeriesList, error) {
	if !timerange.IsValid() {
		return api.SeriesList{}, errors.New("Invalid context.Timerange")
	}

	series := make([]float64, timerange.Slots())
	for i := range series {
		series[i] = float64(value)
	}

	return api.SeriesList{
		Series:    []api.Timeseries{api.Timeseries{series, api.NewTagSet()}},
		Timerange: timerange,
	}, nil
}

func (value scalarValue) toString() (string, error) {
	return "", conversionError{"scalar", "string"}
}

func (value scalarValue) toScalar() (float64, error) {
	return float64(value), nil
}

// Expression is a piece of code, which can be evaluated in a given
// EvaluationContext. EvaluationContext must never be changed in an Evalute().
//
// The contract of Expressions is that leaf nodes must sample a resulting
// timeseries according to the resolution specified in its EvaluationContext's
// Timerange. Internal nodes may assume that results from evaluating child
// Expressions correspond to the timerange in the current EvaluationContext.
type Expression interface {
	// Evaluate the given expression.
	Evaluate(context EvaluationContext) (value, error)
}

func evaluateToSeriesList(e Expression, context EvaluationContext) (api.SeriesList, error) {
	value, err := e.Evaluate(context)
	if err != nil {
		return api.SeriesList{}, err
	}
	return value.toSeriesList(context.Timerange)
}

// Implementations
// ===============

// Generates a Timeseries from the encapsulated scalar.
func (expr scalarExpression) Evaluate(context EvaluationContext) (value, error) {
	return scalarValue(expr.value), nil
}

func (expr *metricFetchExpression) Evaluate(context EvaluationContext) (value, error) {
	// Merge predicates appropriately
	var predicate api.Predicate
	if context.Predicate == nil {
		predicate = expr.predicate
	} else if expr.predicate == nil {
		predicate = context.Predicate
	} else {
		predicate = &andPredicate{[]api.Predicate{expr.predicate, context.Predicate}}
	}

	series, err := context.Backend.FetchSeries(api.TaggedMetric{api.MetricKey(expr.metricName), nil}, predicate, context.SampleMethod, context.Timerange)
	if err != nil {
		return seriesListValue{}, err
	}
	return seriesListValue(*series), err
}

func (expr *functionExpression) Evaluate(context EvaluationContext) (value, error) {
	arguments := make([]value, len(expr.arguments))
	var err error
	for i := range arguments {
		arguments[i], err = expr.arguments[i].Evaluate(context)
		if err != nil {
			return nil, err
		}
	}
	name := expr.functionName
	switch name {
	case "+":
		fallthrough
	case "-":
		fallthrough
	case "*":
		fallthrough
	case "/":
		// Evaluation of a binary operator:
		if len(arguments) != 2 {
			return nil, errors.New(fmt.Sprintf("Function `%s` expects 2 operands but received %d (%+v)", name, len(arguments), arguments))
		}
		left := arguments[0]
		right := arguments[1]
		operatorMap := map[string]func(float64, float64) float64{
			"+": func(x, y float64) float64 { return x + y },
			"-": func(x, y float64) float64 { return x - y },
			"*": func(x, y float64) float64 { return x * y },
			"/": func(x, y float64) float64 { return x / y },
		}
		return evaluateBinaryOperation(context, name, left, right, operatorMap[name])
	default:
		return nil, errors.New(fmt.Sprintf("Invalid function: %s", expr.functionName))
	}
}

//
// Auxiliary functions
//

// evaluateExpression wraps expr.Evaluate() to provide common messaging
// for errors. This can get pretty messy if the Expression we evaluate
// isn't a leaf node, but a leaf fails.
func evaluateExpression(context EvaluationContext, expr Expression) (value, error) {
	result, err := expr.Evaluate(context)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Evaluation of expression %+v failed:\n%s\n", expr, err.Error()))
	}
	return result, err
}

// evaluateBinaryOperation applies an arbirary binary operation to two
// Expressions.
func evaluateBinaryOperation(
	context EvaluationContext,
	functionName string,
	leftValue value,
	rightValue value,
	evaluate func(float64, float64) float64,
) (value, error) {

	leftList, err := leftValue.toSeriesList(context.Timerange)
	if err != nil {
		return nil, err
	}
	rightList, err := rightValue.toSeriesList(context.Timerange)
	if err != nil {
		return nil, err
	}

	joined := join([]api.SeriesList{leftList, rightList})

	result := make([]api.Timeseries, len(joined.Rows))

	for i, row := range joined.Rows {
		left := row.Row[0]
		right := row.Row[1]
		array := make([]float64, len(left.Values))
		for j := 0; j < len(left.Values); j++ {
			array[j] = evaluate(left.Values[j], right.Values[j])
		}
		result[i] = api.Timeseries{array, row.TagSet}
	}

	return seriesListValue(api.SeriesList{
		Series:    result,
		Timerange: context.Timerange,
	}), nil
}

// evaluateExpressions evaluates all provided Expressions in the
// EvaluationContext. If any evaluations error, evaluateExpressions will
// propagate that error. The resulting SeriesLists will be in an order
// corresponding to the provided Expresesions.
func evaluateExpressions(context EvaluationContext, expressions []Expression) ([]value, error) {
	if len(expressions) == 0 {
		return []value{}, nil
	}

	results := make([]value, len(expressions))
	for i, expr := range expressions {
		result, err := expr.Evaluate(context)
		if err != nil {
			return nil, err
		}

		results[i] = result
	}

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

package query

import (
	"errors"
	"fmt"

	"github.com/square/metrics/api"
)

// EvaluationContext is the central piece of logic, providing
// helper funcions & varaibles to evaluate a given piece of
// metrics query.
// * Contains Backend object, which can be used to fetch data
// from the backend system.s
// * Contains current timerange being queried for - this can be
// changed by say, application of time shift function.
type EvaluationContext struct {
	// Backend to fetch data from
	Backend api.Backend
	// Timerange to fetch data from
	Timerange api.Timerange
	// SampleMethod to use when up/downsampling to match the requested resolution
	SampleMethod api.SampleMethod
	Predicate    api.Predicate
}

// A value is the result of evaluating an expression.
// They can be floating point values, strings, or series lists.
type value interface {
	toSeriesList(api.Timerange) (api.SeriesList, error)
	toString() (string, error)
	toScalar() (float64, error)
}

type conversionError struct {
	from string
	to   string
}

func (e conversionError) Error() string {
	return fmt.Sprintf("cannot convert from type %s to type %s", e.from, e.to)
}

// A seriesListValue is a value which holds a SeriesList
type seriesListValue api.SeriesList

func (value seriesListValue) toSeriesList(time api.Timerange) (api.SeriesList, error) {
	return api.SeriesList(value), nil
}
func (value seriesListValue) toString() (string, error) {
	return "", conversionError{"SeriesList", "string"}
}
func (value seriesListValue) toScalar() (float64, error) {
	return 0, conversionError{"SeriesList", "scalar"}
}

// A stringValue holds a string
type stringValue string

func (value stringValue) toSeriesList(time api.Timerange) (api.SeriesList, error) {
	return api.SeriesList{}, conversionError{"string", "SeriesList"}
}
func (value stringValue) toString() (string, error) {
	return string(value), nil
}
func (value stringValue) toScalar() (float64, error) {
	return 0, conversionError{"string", "scalar"}
}

// A scalarValue holds a float and can be converted to a serieslist
type scalarValue float64

func (value scalarValue) toSeriesList(timerange api.Timerange) (api.SeriesList, error) {
	if !timerange.IsValid() {
		return api.SeriesList{}, errors.New("Invalid context.Timerange")
	}

	series := make([]float64, timerange.Slots())
	for i := range series {
		series[i] = float64(value)
	}

	return api.SeriesList{
		Series:    []api.Timeseries{api.Timeseries{series, api.NewTagSet()}},
		Timerange: timerange,
	}, nil
}

func (value scalarValue) toString() (string, error) {
	return "", conversionError{"scalar", "string"}
}

func (value scalarValue) toScalar() (float64, error) {
	return float64(value), nil
}

// Expression is a piece of code, which can be evaluated in a given
// EvaluationContext. EvaluationContext must never be changed in an Evalute().
//
// The contract of Expressions is that leaf nodes must sample a resulting
// timeseries according to the resolution specified in its EvaluationContext's
// Timerange. Internal nodes may assume that results from evaluating child
// Expressions correspond to the timerange in the current EvaluationContext.
type Expression interface {
	// Evaluate the given expression.
	Evaluate(context EvaluationContext) (value, error)
}

func evaluateToSeriesList(e Expression, context EvaluationContext) (api.SeriesList, error) {
	value, err := e.Evaluate(context)
	if err != nil {
		return api.SeriesList{}, err
	}
	return value.toSeriesList(context.Timerange)
}

// Implementations
// ===============

// Generates a Timeseries from the encapsulated scalar.
func (expr scalarExpression) Evaluate(context EvaluationContext) (value, error) {
	return scalarValue(expr.value), nil
}

func (expr *metricFetchExpression) Evaluate(context EvaluationContext) (value, error) {
	// Merge predicates appropriately
	var predicate api.Predicate
	if context.Predicate == nil {
		predicate = expr.predicate
	} else if expr.predicate == nil {
		predicate = context.Predicate
	} else {
		predicate = &andPredicate{[]api.Predicate{expr.predicate, context.Predicate}}
	}

	series, err := context.Backend.FetchSeries(api.TaggedMetric{api.MetricKey(expr.metricName), nil}, predicate, context.SampleMethod, context.Timerange)
	if err != nil {
		return seriesListValue{}, err
	}
	return seriesListValue(*series), err
}

func (expr *functionExpression) Evaluate(context EvaluationContext) (value, error) {
	arguments := make([]value, len(expr.arguments))
	var err error
	for i := range arguments {
		arguments[i], err = expr.arguments[i].Evaluate(context)
		if err != nil {
			return nil, err
		}
	}
	name := expr.functionName
	switch name {
	case "+":
		fallthrough
	case "-":
		fallthrough
	case "*":
		fallthrough
	case "/":
		// Evaluation of a binary operator:
		if len(arguments) != 2 {
			return nil, errors.New(fmt.Sprintf("Function `%s` expects 2 operands but received %d (%+v)", name, len(arguments), arguments))
		}
		left := arguments[0]
		right := arguments[1]
		operatorMap := map[string]func(float64, float64) float64{
			"+": func(x, y float64) float64 { return x + y },
			"-": func(x, y float64) float64 { return x - y },
			"*": func(x, y float64) float64 { return x * y },
			"/": func(x, y float64) float64 { return x / y },
		}
		return evaluateBinaryOperation(context, name, left, right, operatorMap[name])
	case "aggregate.sum":
		if len(arguments) != 1 {
			return nil, errors.New(fmt.Sprintf("Function `%s` expected 2 operands but received %d (%+v)", name, len(arguments), arguments))
		}
		list, err := arguments[0].toSeriesList(context.Timerange)
		if err != nil {
			return nil, err
		}
		return seriesListValue(aggregateBy(list, aggregateMap[sumAggregate], expr.groupBy)), nil
	default:
		return nil, errors.New(fmt.Sprintf("Invalid function: %s", expr.functionName))
	}
}

//
// Auxiliary functions
//

// evaluateExpression wraps expr.Evaluate() to provide common messaging
// for errors. This can get pretty messy if the Expression we evaluate
// isn't a leaf node, but a leaf fails.
func evaluateExpression(context EvaluationContext, expr Expression) (value, error) {
	result, err := expr.Evaluate(context)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Evaluation of expression %+v failed:\n%s\n", expr, err.Error()))
	}
	return result, err
}

// evaluateBinaryOperation applies an arbirary binary operation to two
// Expressions.
func evaluateBinaryOperation(
	context EvaluationContext,
	functionName string,
	leftValue value,
	rightValue value,
	evaluate func(float64, float64) float64,
) (value, error) {

	leftList, err := leftValue.toSeriesList(context.Timerange)
	if err != nil {
		return nil, err
	}
	rightList, err := rightValue.toSeriesList(context.Timerange)
	if err != nil {
		return nil, err
	}

	joined := join([]api.SeriesList{leftList, rightList})

	result := make([]api.Timeseries, len(joined.Rows))

	for i, row := range joined.Rows {
		left := row.Row[0]
		right := row.Row[1]
		array := make([]float64, len(left.Values))
		for j := 0; j < len(left.Values); j++ {
			array[j] = evaluate(left.Values[j], right.Values[j])
		}
		result[i] = api.Timeseries{array, row.TagSet}
	}

	return seriesListValue(api.SeriesList{
		Series:    result,
		Timerange: context.Timerange,
	}), nil
}

// evaluateExpressions evaluates all provided Expressions in the
// EvaluationContext. If any evaluations error, evaluateExpressions will
// propagate that error. The resulting SeriesLists will be in an order
// corresponding to the provided Expresesions.
func evaluateExpressions(context EvaluationContext, expressions []Expression) ([]value, error) {
	if len(expressions) == 0 {
		return []value{}, nil
	}

	results := make([]value, len(expressions))
	for i, expr := range expressions {
		result, err := expr.Evaluate(context)
		if err != nil {
			return nil, err
		}

		results[i] = result
	}

	return results, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/scbizu/Astral/telegram"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

//LaunchCmd impl Launch Command
var LaunchCmd = &cobra.Command{
	Use:   "astral",
	Short: "Launch astral",
	Long:  "Launch command",
	Run: func(cmd *cobra.Command, args []string) {

		// if err := telegram.PullAndReply(); err != nil {
		// 	log.Fatal(err)
		// }

		if err := telegram.ListenWebHook(true); err != nil {
			logrus.Fatal(err)
		}

		return
	},
}

//Execute exec astral
func Execute() (err error) {
	err = LaunchCmd.Execute()
	return
}
<commit_msg>cmd: remove tl pull mode<commit_after>package cmd

import (
	"github.com/scbizu/Astral/telegram"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
)

//LaunchCmd impl Launch Command
var LaunchCmd = &cobra.Command{
	Use:   "astral",
	Short: "Launch astral",
	Long:  "Launch command",
	Run: func(cmd *cobra.Command, args []string) {

		if err := telegram.ListenWebHook(true); err != nil {
			logrus.Fatal(err)
		}

		return
	},
}

//Execute exec astral
func Execute() (err error) {
	err = LaunchCmd.Execute()
	return
}
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

var pagenation int
var argument string

type Qiita struct {
	Title string `json: "title"`
	Url   string `json: "url"`
}

var searchCmd = &cobra.Command{
	Use:   "search",
	Short: "Call Api of Qiita",
	Long:  "Call Api of Qiita",
	Run: func(cmd *cobra.Command, args []string) {
		pagenation = 1
		argument = strings.Join(args, ",")
		resp, err := http.Get("http://qiita.com/api/v2/items?page=" + strconv.Itoa(pagenation) + "&per_page=10&query=" + argument)
		if err == nil {
			puts(resp)
		} else {
			fmt.Println(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(searchCmd)
}

func puts(resp *http.Response) {
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err == nil {
		var content interface{}
		json.Unmarshal(b, &content)
		for i := 0; i < 10; i++ {
			fmt.Print(color.YellowString(strconv.Itoa(i) + " -> "))
			fmt.Println(content.([]interface{})[i].(map[string]interface{})["title"].(string))
		}
		var num int
		fmt.Print("SELECT > ")
		_, errr := fmt.Scanf("%d", &num)
		if errr == nil {
			errrr := exec.Command("open", content.([]interface{})[num].(map[string]interface{})["url"].(string)).Run()
			if errrr != nil {
				fmt.Println(errrr)
			}
		}
	} else {
		fmt.Println(err)
	}
}
<commit_msg>Add next number<commit_after>package cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"strings"

	"github.com/fatih/color"
	"github.com/spf13/cobra"
)

var pagenation int
var argument string

type Qiita struct {
	Title string `json: "title"`
	Url   string `json: "url"`
}

var searchCmd = &cobra.Command{
	Use:   "search",
	Short: "Call Api of Qiita",
	Long:  "Call Api of Qiita",
	Run: func(cmd *cobra.Command, args []string) {
		pagenation = 1
		argument = strings.Join(args, ",")
		resp, err := http.Get("http://qiita.com/api/v2/items?page=" + strconv.Itoa(pagenation) + "&per_page=10&query=" + argument)
		if err == nil {
			puts(resp)
		} else {
			fmt.Println(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(searchCmd)
}

func puts(resp *http.Response) {
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err == nil {
		var content interface{}
		json.Unmarshal(b, &content)
		for i := 0; i < 10; i++ {
			fmt.Print(color.YellowString(strconv.Itoa(i) + " -> "))
			fmt.Println(content.([]interface{})[i].(map[string]interface{})["title"].(string))
		}
		var num string
		fmt.Println(color.YellowString("n -> ") + "next page")
		fmt.Print("SELECT > ")
		_, errr := fmt.Scanf("%s", &num)
		number, _ := strconv.Atoi(num)
		if errr == nil {
			errrr := exec.Command("open", content.([]interface{})[number].(map[string]interface{})["url"].(string)).Run()
			if errrr != nil {
				fmt.Println(errrr)
			}
		}
	} else {
		fmt.Println(err)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"context"
	"fmt"
	"strings"

	"github.com/arigatomachine/cli/api"
	"github.com/arigatomachine/cli/apitypes"
	"github.com/arigatomachine/cli/config"
	"github.com/arigatomachine/cli/errs"

	"github.com/urfave/cli"
)

func init() {
	signup := cli.Command{
		Name:      "signup",
		Usage:     "Create a new Torus account which, while in alpha, requires an invite code",
		ArgsUsage: "[email] [code]",
		Category:  "ACCOUNT",
		Action:    chain(ensureDaemon, signupCmd),
	}
	Cmds = append(Cmds, signup)
}

func signupCmd(ctx *cli.Context) error {
	return signup(ctx, false)
}

// signup can be ran as a sub-command when an account is needed prior to running
// a particular action. the subCommand boolean signifies it is running as such
// and not as a generic signup
func signup(ctx *cli.Context, subCommand bool) error {
	args := ctx.Args()
	if len(args) > 0 && len(args) != 2 {
		var text string
		if len(args) > 2 {
			text = "Too many arguments supplied."
		} else {
			text = "Too few arguments supplied."
		}
		return errs.NewUsageExitError(text, ctx)
	}

	name, err := FullNamePrompt()
	if err != nil {
		return err
	}

	username, err := UsernamePrompt()
	if err != nil {
		return err
	}

	defaultEmail := ""
	defaultInvite := ""
	if len(args) == 2 {
		defaultEmail = args[0]
		defaultInvite = args[1]
	}

	email, err := EmailPrompt(defaultEmail)
	if err != nil {
		return err
	}

	var inviteCode string
	if subCommand {
		inviteCode, err = InviteCodePrompt(defaultInvite)
		if err != nil {
			return err
		}
	}

	password, err := PasswordPrompt(true)
	if err != nil {
		return err
	}

	cfg, err := config.LoadConfig()
	if err != nil {
		return err
	}

	client := api.NewClient(cfg)

	signup := apitypes.Signup{
		Name:       name,
		Username:   username,
		Passphrase: password,
		Email:      email,
		InviteCode: inviteCode,
		OrgName:    ctx.String("org"),
		OrgInvite:  subCommand,
	}

	c := context.Background()

	fmt.Println("")
	user, err := client.Users.Signup(c, &signup, &progress)
	if err != nil {
		if strings.Contains(err.Error(), "resource exists") {
			return errs.NewExitError("Email address in use.")
		}
		return errs.NewExitError("Signup failed, please try again.")
	}

	// Log the user in
	err = performLogin(c, client, user.Body.Email, password)
	if err != nil {
		return err
	}

	// Generate keypairs, look up the user's org
	err = generateKeypairsForOrg(c, ctx, client, nil, true)
	if err != nil {
		return err
	}

	fmt.Println("")
	fmt.Println("Your account has been created!")

	if !subCommand {
		fmt.Println("")
		fmt.Println("We have emailed you a verification code.")
		fmt.Println("Please verify your email address by entering the code below.")
		fmt.Println("")

		code, err := VerificationPrompt()
		if err != nil {
			return err
		}
		fmt.Println("")

		err = verifyEmail(ctx, &code, true)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Remove alpha from signup help text<commit_after>package cmd

import (
	"context"
	"fmt"
	"strings"

	"github.com/arigatomachine/cli/api"
	"github.com/arigatomachine/cli/apitypes"
	"github.com/arigatomachine/cli/config"
	"github.com/arigatomachine/cli/errs"

	"github.com/urfave/cli"
)

func init() {
	signup := cli.Command{
		Name:      "signup",
		Usage:     "Create a new Torus account",
		ArgsUsage: "[email] [code]",
		Category:  "ACCOUNT",
		Action:    chain(ensureDaemon, signupCmd),
	}
	Cmds = append(Cmds, signup)
}

func signupCmd(ctx *cli.Context) error {
	return signup(ctx, false)
}

// signup can be ran as a sub-command when an account is needed prior to running
// a particular action. the subCommand boolean signifies it is running as such
// and not as a generic signup
func signup(ctx *cli.Context, subCommand bool) error {
	args := ctx.Args()
	if len(args) > 0 && len(args) != 2 {
		var text string
		if len(args) > 2 {
			text = "Too many arguments supplied."
		} else {
			text = "Too few arguments supplied."
		}
		return errs.NewUsageExitError(text, ctx)
	}

	name, err := FullNamePrompt()
	if err != nil {
		return err
	}

	username, err := UsernamePrompt()
	if err != nil {
		return err
	}

	defaultEmail := ""
	defaultInvite := ""
	if len(args) == 2 {
		defaultEmail = args[0]
		defaultInvite = args[1]
	}

	email, err := EmailPrompt(defaultEmail)
	if err != nil {
		return err
	}

	var inviteCode string
	if subCommand {
		inviteCode, err = InviteCodePrompt(defaultInvite)
		if err != nil {
			return err
		}
	}

	password, err := PasswordPrompt(true)
	if err != nil {
		return err
	}

	cfg, err := config.LoadConfig()
	if err != nil {
		return err
	}

	client := api.NewClient(cfg)

	signup := apitypes.Signup{
		Name:       name,
		Username:   username,
		Passphrase: password,
		Email:      email,
		InviteCode: inviteCode,
		OrgName:    ctx.String("org"),
		OrgInvite:  subCommand,
	}

	c := context.Background()

	fmt.Println("")
	user, err := client.Users.Signup(c, &signup, &progress)
	if err != nil {
		if strings.Contains(err.Error(), "resource exists") {
			return errs.NewExitError("Email address in use.")
		}
		return errs.NewExitError("Signup failed, please try again.")
	}

	// Log the user in
	err = performLogin(c, client, user.Body.Email, password)
	if err != nil {
		return err
	}

	// Generate keypairs, look up the user's org
	err = generateKeypairsForOrg(c, ctx, client, nil, true)
	if err != nil {
		return err
	}

	fmt.Println("")
	fmt.Println("Your account has been created!")

	if !subCommand {
		fmt.Println("")
		fmt.Println("We have emailed you a verification code.")
		fmt.Println("Please verify your email address by entering the code below.")
		fmt.Println("")

		code, err := VerificationPrompt()
		if err != nil {
			return err
		}
		fmt.Println("")

		err = verifyEmail(ctx, &code, true)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/spf13/cobra"
)

type workerDone struct{}

type requestStat struct {
	duration int64 //nanoseconds
}
type requestStatSummary struct {
	avgQps      float64 //per nanoseconds
	avgDuration int64   //nanoseconds
	maxDuration int64   //nanoseconds
	minDuration int64   //nanoseconds
}

//verbose levels
const (
	VerboseNone = iota
	VerboseLow
	VerboseMedium
	VerboseHigh
)

//flags
var (
	numTests      int
	timeout       int
	concurrency   int
	requestMethod string
	verboseLevel  int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 100, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
	stressCmd.Flags().StringVarP(&requestMethod, "requestMethod", "X", "GET", "Request type. GET, HEAD, POST, PUT, etc.")
	stressCmd.Flags().IntVarP(&verboseLevel, "verbose", "v", 0, "Level of verbosity ("+strconv.Itoa(VerboseNone)+"-"+strconv.Itoa(VerboseHigh)+")")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  runStress,
}

func runStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}
	if concurrency > numTests {
		return errors.New("concurrency must be higher than number of requests")
	}
	if verboseLevel < VerboseNone || verboseLevel > VerboseHigh {
		return errors.New("verbose level must be between " + strconv.Itoa(VerboseNone) + " and " + strconv.Itoa(VerboseHigh))
	}

	url := args[0]

	fmt.Println("Stress testing " + url + "...")

	//setup the request
	req, err := http.NewRequest(requestMethod, url, nil)
	if err != nil {
		return errors.New("failed to create request: " + err.Error())
	}

	//info about the request
	if verboseLevel >= VerboseMedium {
		fmt.Println(req.Proto)
		fmt.Println("Method: " + req.Method)
		fmt.Println("Host: " + req.Host)
	}

	//setup the queue of requests
	requestChan := make(chan *http.Request, numTests)
	for i := 0; i < numTests; i++ {
		requestChan <- req
	}
	close(requestChan)

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	totalStartTime := time.Now()
	for i := 0; i < concurrency; i++ {
		//TODO handle the returned errors from this
		go func() error {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req, ok := <-requestChan:
					if !ok {
						workerDoneChan <- workerDone{}
						return nil
					}
					//run the acutal request
					reqStartTime := time.Now()
					response, err := client.Do((*http.Request)(req))
					reqEndTime := time.Now()
					if err != nil {
						return errors.New("Failed to make request:" + err.Error())
					}
					reqTimeNs := (reqEndTime.UnixNano() - reqStartTime.UnixNano())

					var requestData string
					if verboseLevel >= VerboseLow {
						requestData = "--------\n\n"
					}
					if verboseLevel >= VerboseLow {
						//request timing
						requestData = requestData + fmt.Sprintf("Request took %dms\n\n", reqTimeNs/1000000)
					}
					if verboseLevel >= VerboseMedium {
						//reponse metadata
						requestData = requestData + fmt.Sprintf("Response:\n%+v\n\n", response)
					}
					if verboseLevel >= VerboseHigh {
						//reponse body
						defer response.Body.Close()
						body, err := ioutil.ReadAll(response.Body)
						if err != nil {
							return errors.New("Failed to read response body:" + err.Error())
						}
						requestData = requestData + fmt.Sprintf("Body:\n%s\n\n", body)
					}

					if requestData != "" {
						fmt.Print(requestData)
					}
					requestStatChan <- requestStat{duration: reqTimeNs}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				totalEndTime := time.Now()

				totalTimeNs := totalEndTime.UnixNano() - totalStartTime.UnixNano()
				reqStats := createRequestsStats(allRequestStats, totalTimeNs)
				fmt.Println(createTextSummary(reqStats, totalTimeNs))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}
}

//create statistical summary of all requests
func createRequestsStats(requestStats []requestStat, totalTimeNs int64) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{maxDuration: requestStats[0].duration, minDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0 //total time of all requests (concurrent is counted)
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.maxDuration {
			summary.maxDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.minDuration {
			summary.minDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	summary.avgQps = float64(len(requestStats)) / float64(totalTimeNs)
	return summary
}

//creates nice readable summary of entire stress test
func createTextSummary(reqStatSummary requestStatSummary, totalTimeNs int64) string {
	summary := "\n"

	summary = summary + "Runtime Statistics:\n"
	summary = summary + "Total time:  " + strconv.Itoa(int(totalTimeNs/1000000)) + " ms\n"
	summary = summary + "Mean QPS:    " + fmt.Sprintf("%.2f", reqStatSummary.avgQps*1000000000) + " req/sec\n"

	summary = summary + "\nQuery Statistics\n"
	summary = summary + "Mean query:     " + strconv.Itoa(int(reqStatSummary.avgDuration/1000000)) + " ms\n"
	summary = summary + "Fastest query:  " + strconv.Itoa(int(reqStatSummary.minDuration/1000000)) + " ms\n"
	summary = summary + "Slowest query:  " + strconv.Itoa(int(reqStatSummary.maxDuration/1000000)) + " ms\n"
	return summary
}
<commit_msg>Changing default count to 1 request<commit_after>package cmd

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"time"

	"github.com/spf13/cobra"
)

type workerDone struct{}

type requestStat struct {
	duration int64 //nanoseconds
}
type requestStatSummary struct {
	avgQps      float64 //per nanoseconds
	avgDuration int64   //nanoseconds
	maxDuration int64   //nanoseconds
	minDuration int64   //nanoseconds
}

//verbose levels
const (
	VerboseNone = iota
	VerboseLow
	VerboseMedium
	VerboseHigh
)

//flags
var (
	numTests      int
	timeout       int
	concurrency   int
	requestMethod string
	verboseLevel  int
)

func init() {
	RootCmd.AddCommand(stressCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// stressCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// stressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

	stressCmd.Flags().IntVarP(&numTests, "num", "n", 1, "Number of requests to make")
	stressCmd.Flags().IntVarP(&concurrency, "concurrent", "c", 1, "Number of multiple requests to make")
	stressCmd.Flags().IntVarP(&timeout, "timeout", "t", 0, "Maximum seconds to wait for response. 0 means unlimited")
	stressCmd.Flags().StringVarP(&requestMethod, "requestMethod", "X", "GET", "Request type. GET, HEAD, POST, PUT, etc.")
	stressCmd.Flags().IntVarP(&verboseLevel, "verbose", "v", 0, "Level of verbosity ("+strconv.Itoa(VerboseNone)+"-"+strconv.Itoa(VerboseHigh)+")")
}

// stressCmd represents the stress command
var stressCmd = &cobra.Command{
	Use:   "stress http[s]://hostname[:port]/path",
	Short: "Run predefined load of requests",
	Long:  `Run predefined load of requests`,
	RunE:  runStress,
}

func runStress(cmd *cobra.Command, args []string) error {
	//checks
	if len(args) != 1 {
		return errors.New("needs URL")
	}
	if numTests <= 0 {
		return errors.New("number of requests must be one or more")
	}
	if concurrency <= 0 {
		return errors.New("concurrency must be one or more")
	}
	if timeout < 0 {
		return errors.New("timeout must be zero or more")
	}
	if concurrency > numTests {
		return errors.New("concurrency must be higher than number of requests")
	}
	if verboseLevel < VerboseNone || verboseLevel > VerboseHigh {
		return errors.New("verbose level must be between " + strconv.Itoa(VerboseNone) + " and " + strconv.Itoa(VerboseHigh))
	}

	url := args[0]

	fmt.Println("Stress testing " + url + "...")

	//setup the request
	req, err := http.NewRequest(requestMethod, url, nil)
	if err != nil {
		return errors.New("failed to create request: " + err.Error())
	}

	//info about the request
	if verboseLevel >= VerboseMedium {
		fmt.Println(req.Proto)
		fmt.Println("Method: " + req.Method)
		fmt.Println("Host: " + req.Host)
	}

	//setup the queue of requests
	requestChan := make(chan *http.Request, numTests)
	for i := 0; i < numTests; i++ {
		requestChan <- req
	}
	close(requestChan)

	workerDoneChan := make(chan workerDone)   //workers use this to indicate they are done
	requestStatChan := make(chan requestStat) //workers communicate each requests' info

	//workers
	totalStartTime := time.Now()
	for i := 0; i < concurrency; i++ {
		//TODO handle the returned errors from this
		go func() error {
			client := &http.Client{Timeout: time.Duration(timeout) * time.Second}
			for {
				select {
				case req, ok := <-requestChan:
					if !ok {
						workerDoneChan <- workerDone{}
						return nil
					}
					//run the acutal request
					reqStartTime := time.Now()
					response, err := client.Do((*http.Request)(req))
					reqEndTime := time.Now()
					if err != nil {
						return errors.New("Failed to make request:" + err.Error())
					}
					reqTimeNs := (reqEndTime.UnixNano() - reqStartTime.UnixNano())

					var requestData string
					if verboseLevel >= VerboseLow {
						requestData = "--------\n\n"
					}
					if verboseLevel >= VerboseLow {
						//request timing
						requestData = requestData + fmt.Sprintf("Request took %dms\n\n", reqTimeNs/1000000)
					}
					if verboseLevel >= VerboseMedium {
						//reponse metadata
						requestData = requestData + fmt.Sprintf("Response:\n%+v\n\n", response)
					}
					if verboseLevel >= VerboseHigh {
						//reponse body
						defer response.Body.Close()
						body, err := ioutil.ReadAll(response.Body)
						if err != nil {
							return errors.New("Failed to read response body:" + err.Error())
						}
						requestData = requestData + fmt.Sprintf("Body:\n%s\n\n", body)
					}

					if requestData != "" {
						fmt.Print(requestData)
					}
					requestStatChan <- requestStat{duration: reqTimeNs}
				}
			}
		}()
	}

	allRequestStats := make([]requestStat, numTests)
	requestsCompleteCount := 0
	workersDoneCount := 0
	//wait for all workers to finish
	for {
		select {
		case <-workerDoneChan:
			workersDoneCount++
			if workersDoneCount == concurrency {
				//all workers are done
				totalEndTime := time.Now()

				totalTimeNs := totalEndTime.UnixNano() - totalStartTime.UnixNano()
				reqStats := createRequestsStats(allRequestStats, totalTimeNs)
				fmt.Println(createTextSummary(reqStats, totalTimeNs))
				return nil
			}
		case requestStat := <-requestStatChan:
			allRequestStats[requestsCompleteCount] = requestStat
			requestsCompleteCount++
		}
	}
}

//create statistical summary of all requests
func createRequestsStats(requestStats []requestStat, totalTimeNs int64) requestStatSummary {
	if len(requestStats) == 0 {
		return requestStatSummary{}
	}

	summary := requestStatSummary{maxDuration: requestStats[0].duration, minDuration: requestStats[0].duration}
	var totalDurations int64
	totalDurations = 0 //total time of all requests (concurrent is counted)
	for i := 0; i < len(requestStats); i++ {
		if requestStats[i].duration > summary.maxDuration {
			summary.maxDuration = requestStats[i].duration
		}
		if requestStats[i].duration < summary.minDuration {
			summary.minDuration = requestStats[i].duration
		}
		totalDurations += requestStats[i].duration
	}
	summary.avgDuration = totalDurations / int64(len(requestStats))
	summary.avgQps = float64(len(requestStats)) / float64(totalTimeNs)
	return summary
}

//creates nice readable summary of entire stress test
func createTextSummary(reqStatSummary requestStatSummary, totalTimeNs int64) string {
	summary := "\n"

	summary = summary + "Runtime Statistics:\n"
	summary = summary + "Total time:  " + strconv.Itoa(int(totalTimeNs/1000000)) + " ms\n"
	summary = summary + "Mean QPS:    " + fmt.Sprintf("%.2f", reqStatSummary.avgQps*1000000000) + " req/sec\n"

	summary = summary + "\nQuery Statistics\n"
	summary = summary + "Mean query:     " + strconv.Itoa(int(reqStatSummary.avgDuration/1000000)) + " ms\n"
	summary = summary + "Fastest query:  " + strconv.Itoa(int(reqStatSummary.minDuration/1000000)) + " ms\n"
	summary = summary + "Slowest query:  " + strconv.Itoa(int(reqStatSummary.maxDuration/1000000)) + " ms\n"
	return summary
}
<|endoftext|>


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

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

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

// TODO: don't use a global state to allow concurrent use
var c *cache

func implementsIface(sign *types.Signature) bool {
	s := signString(sign)
	_, e := funcs[s]
	return e
}

func doMethoderType(t types.Type) map[string]string {
	switch x := t.(type) {
	case *types.Pointer:
		return doMethoderType(x.Elem())
	case *types.Named:
		if u, ok := x.Underlying().(*types.Interface); ok {
			return doMethoderType(u)
		}
		return namedMethodMap(x)
	case *types.Interface:
		return ifaceFuncMap(x)
	default:
		return nil
	}
}

func assignable(s, t string, called, want map[string]string) bool {
	if s == t {
		return true
	}
	if len(t) >= len(s) {
		return false
	}
	for fname, ftype := range want {
		s, e := called[fname]
		if !e || s != ftype {
			return false
		}
	}
	return true
}

func interfaceMatching(obj types.Object, p *param) (string, string) {
	for to := range p.assigned {
		if to.discard {
			return "", ""
		}
	}
	allFuncs := doMethoderType(obj.Type())
	called := make(map[string]string, len(p.calls))
	for fname := range p.calls {
		called[fname] = allFuncs[fname]
	}
	s := funcMapString(called)
	name, e := ifaces[s]
	if !e {
		return "", ""
	}
	for t := range p.usedAs {
		iface, ok := t.(*types.Interface)
		if !ok {
			return "", ""
		}
		asMethods := ifaceFuncMap(iface)
		as := funcMapString(asMethods)
		if !assignable(s, as, called, asMethods) {
			return "", ""
		}
	}
	return name, s
}

func orderedPkgs(prog *loader.Program) ([]*types.Package, error) {
	// TODO: InitialPackages() is not in the order that we passed to
	// it via Import() calls.
	// For now, make it deterministic by sorting by import path.
	unordered := prog.InitialPackages()
	paths := make([]string, 0, len(unordered))
	byPath := make(map[string]*types.Package, len(unordered))
	for _, info := range unordered {
		if info.Errors != nil {
			return nil, info.Errors[0]
		}
		path := info.Pkg.Path()
		paths = append(paths, path)
		byPath[path] = info.Pkg
	}
	sort.Sort(ByAlph(paths))
	pkgs := make([]*types.Package, 0, len(unordered))
	for _, path := range paths {
		pkgs = append(pkgs, byPath[path])
	}
	return pkgs, nil
}

// relPathErr makes converts errors by go/types and go/loader that use
// absolute paths into errors with relative paths
func relPathErr(err error) error {
	errStr := fmt.Sprintf("%v", err)
	if !strings.HasPrefix(errStr, "/") {
		return err
	}
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	if strings.HasPrefix(errStr, wd) {
		return fmt.Errorf(errStr[len(wd)+1:])
	}
	return err
}

func CheckArgs(args []string, w io.Writer, verbose bool) error {
	paths, err := recurse(args)
	if err != nil {
		return err
	}
	typesInit()
	if _, err := c.FromArgs(paths, false); err != nil {
		return err
	}
	prog, err := c.Load()
	if err != nil {
		return err
	}
	pkgs, err := orderedPkgs(prog)
	if err != nil {
		return relPathErr(err)
	}
	typesGet(pkgs)
	for _, pkg := range pkgs {
		info := prog.AllPackages[pkg]
		if verbose {
			fmt.Fprintln(w, info.Pkg.Path())
		}
		checkPkg(&c.TypeChecker, info, w)
	}
	return nil
}

func checkPkg(conf *types.Config, info *loader.PackageInfo, w io.Writer) {
	v := &visitor{
		PackageInfo: info,
		w:           w,
		fset:        c.Fset,
	}
	for _, f := range info.Files {
		ast.Walk(v, f)
	}
}

type param struct {
	calls   map[string]struct{}
	usedAs  map[types.Type]struct{}
	discard bool

	assigned map[*param]struct{}
}

type visitor struct {
	*loader.PackageInfo

	w     io.Writer
	fset  *token.FileSet
	signs []*types.Signature

	params  map[types.Object]*param
	extras  map[types.Object]*param
	inBlock bool

	skipNext bool
}

func paramsMap(t *types.Tuple) map[types.Object]*param {
	m := make(map[types.Object]*param, t.Len())
	for i := 0; i < t.Len(); i++ {
		p := t.At(i)
		m[p] = &param{
			calls:    make(map[string]struct{}),
			usedAs:   make(map[types.Type]struct{}),
			assigned: make(map[*param]struct{}),
		}
	}
	return m
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return x.Elem()
	default:
		return x
	}
}

func (v *visitor) param(id *ast.Ident) *param {
	obj := v.ObjectOf(id)
	if obj == nil {
		panic("unexpected nil object found")
	}
	if p, e := v.params[obj]; e {
		return p
	}
	if p, e := v.extras[obj]; e {
		return p
	}
	p := &param{
		calls:    make(map[string]struct{}),
		usedAs:   make(map[types.Type]struct{}),
		assigned: make(map[*param]struct{}),
	}
	v.extras[obj] = p
	return p
}

func (v *visitor) addUsed(id *ast.Ident, as types.Type) {
	if as == nil {
		return
	}
	p := v.param(id)
	p.usedAs[as.Underlying()] = struct{}{}
}

func (v *visitor) addAssign(to, from *ast.Ident) {
	pto := v.param(to)
	pfrom := v.param(from)
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	if !v.inBlock {
		return
	}
	id, ok := e.(*ast.Ident)
	if !ok {
		return
	}
	p := v.param(id)
	p.discard = true
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	if v.skipNext {
		v.skipNext = false
		return nil
	}
	var sign *types.Signature
	switch x := node.(type) {
	case *ast.FuncLit:
		if v.inBlock {
			break
		}
		sign = v.Types[x].Type.(*types.Signature)
		if implementsIface(sign) {
			return nil
		}
		v.params = paramsMap(sign.Params())
		v.extras = make(map[types.Object]*param)
	case *ast.FuncDecl:
		sign = v.Defs[x.Name].Type().(*types.Signature)
		if implementsIface(sign) {
			return nil
		}
		v.params = paramsMap(sign.Params())
		v.extras = make(map[types.Object]*param)
	case *ast.BlockStmt:
		if v.params != nil {
			v.inBlock = true
		}
	case *ast.SelectorExpr:
		v.discard(x.X)
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.BinaryExpr:
		v.discard(x.X)
		v.discard(x.Y)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.AssignStmt:
		if !v.inBlock {
			return nil
		}
		v.onAssign(x)
	case *ast.CallExpr:
		if !v.inBlock {
			return nil
		}
		v.onCall(x)
	case nil:
		top := v.signs[len(v.signs)-1]
		if top != nil {
			v.funcEnded(top)
			v.params = nil
			v.extras = nil
			v.inBlock = false
		}
		v.signs = v.signs[:len(v.signs)-1]
	}
	if node != nil {
		v.signs = append(v.signs, sign)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *visitor) onAssign(as *ast.AssignStmt) {
	for i, e := range as.Rhs {
		id, ok := e.(*ast.Ident)
		if !ok {
			continue
		}
		left := as.Lhs[i]
		v.addUsed(id, v.Types[left].Type)
		if lid, ok := left.(*ast.Ident); ok {
			v.addAssign(lid, id)
		}
	}
}

func (v *visitor) onCall(ce *ast.CallExpr) {
	switch y := ce.Fun.(type) {
	case *ast.Ident:
		v.skipNext = true
	case *ast.SelectorExpr:
		if _, ok := y.X.(*ast.Ident); ok {
			v.skipNext = true
		}
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	for i, e := range ce.Args {
		if id, ok := e.(*ast.Ident); ok {
			v.addUsed(id, paramType(sign, i))
		}
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	p := v.param(left)
	p.calls[sel.Sel.Name] = struct{}{}
	return
}

func (v *visitor) funcEnded(sign *types.Signature) {
	for obj, p := range v.params {
		if p.discard {
			continue
		}
		ifname, iftype := interfaceMatching(obj, p)
		if ifname == "" {
			continue
		}
		t := obj.Type()
		if _, haveIface := t.Underlying().(*types.Interface); haveIface {
			if ifname == t.String() {
				continue
			}
			have := funcMapString(doMethoderType(t))
			if have == iftype {
				continue
			}
		}
		pos := v.fset.Position(obj.Pos())
		fname := pos.Filename
		if fname[0] == '/' {
			fname = filepath.Join(v.Pkg.Path(), filepath.Base(fname))
		}
		pname := v.Pkg.Name()
		if strings.HasPrefix(ifname, pname+".") {
			ifname = ifname[len(pname)+1:]
		}
		fmt.Fprintf(v.w, "%s:%d:%d: %s can be %s\n",
			fname, pos.Line, pos.Column, obj.Name(), ifname)
	}
}
<commit_msg>Unify var maps, remove inBlock<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interfacer

import (
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strings"

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

// TODO: don't use a global state to allow concurrent use
var c *cache

func implementsIface(sign *types.Signature) bool {
	s := signString(sign)
	_, e := funcs[s]
	return e
}

func doMethoderType(t types.Type) map[string]string {
	switch x := t.(type) {
	case *types.Pointer:
		return doMethoderType(x.Elem())
	case *types.Named:
		if u, ok := x.Underlying().(*types.Interface); ok {
			return doMethoderType(u)
		}
		return namedMethodMap(x)
	case *types.Interface:
		return ifaceFuncMap(x)
	default:
		return nil
	}
}

func assignable(s, t string, called, want map[string]string) bool {
	if s == t {
		return true
	}
	if len(t) >= len(s) {
		return false
	}
	for fname, ftype := range want {
		s, e := called[fname]
		if !e || s != ftype {
			return false
		}
	}
	return true
}

func interfaceMatching(obj types.Object, vr *variable) (string, string) {
	for to := range vr.assigned {
		if to.discard {
			return "", ""
		}
	}
	allFuncs := doMethoderType(obj.Type())
	called := make(map[string]string, len(vr.calls))
	for fname := range vr.calls {
		called[fname] = allFuncs[fname]
	}
	s := funcMapString(called)
	name, e := ifaces[s]
	if !e {
		return "", ""
	}
	for t := range vr.usedAs {
		iface, ok := t.(*types.Interface)
		if !ok {
			return "", ""
		}
		asMethods := ifaceFuncMap(iface)
		as := funcMapString(asMethods)
		if !assignable(s, as, called, asMethods) {
			return "", ""
		}
	}
	return name, s
}

func orderedPkgs(prog *loader.Program) ([]*types.Package, error) {
	// TODO: InitialPackages() is not in the order that we passed to
	// it via Import() calls.
	// For now, make it deterministic by sorting by import path.
	unordered := prog.InitialPackages()
	paths := make([]string, 0, len(unordered))
	byPath := make(map[string]*types.Package, len(unordered))
	for _, info := range unordered {
		if info.Errors != nil {
			return nil, info.Errors[0]
		}
		path := info.Pkg.Path()
		paths = append(paths, path)
		byPath[path] = info.Pkg
	}
	sort.Sort(ByAlph(paths))
	pkgs := make([]*types.Package, 0, len(unordered))
	for _, path := range paths {
		pkgs = append(pkgs, byPath[path])
	}
	return pkgs, nil
}

// relPathErr makes converts errors by go/types and go/loader that use
// absolute paths into errors with relative paths
func relPathErr(err error) error {
	errStr := fmt.Sprintf("%v", err)
	if !strings.HasPrefix(errStr, "/") {
		return err
	}
	wd, err := os.Getwd()
	if err != nil {
		return err
	}
	if strings.HasPrefix(errStr, wd) {
		return fmt.Errorf(errStr[len(wd)+1:])
	}
	return err
}

func CheckArgs(args []string, w io.Writer, verbose bool) error {
	paths, err := recurse(args)
	if err != nil {
		return err
	}
	typesInit()
	if _, err := c.FromArgs(paths, false); err != nil {
		return err
	}
	prog, err := c.Load()
	if err != nil {
		return err
	}
	pkgs, err := orderedPkgs(prog)
	if err != nil {
		return relPathErr(err)
	}
	typesGet(pkgs)
	for _, pkg := range pkgs {
		info := prog.AllPackages[pkg]
		if verbose {
			fmt.Fprintln(w, info.Pkg.Path())
		}
		checkPkg(&c.TypeChecker, info, w)
	}
	return nil
}

func checkPkg(conf *types.Config, info *loader.PackageInfo, w io.Writer) {
	v := &visitor{
		PackageInfo: info,
		w:           w,
		fset:        c.Fset,
		vars:        make(map[types.Object]*variable),
	}
	for _, f := range info.Files {
		ast.Walk(v, f)
	}
}

type variable struct {
	calls   map[string]struct{}
	usedAs  map[types.Type]struct{}
	discard bool

	assigned map[*variable]struct{}
}

type visitor struct {
	*loader.PackageInfo

	w     io.Writer
	fset  *token.FileSet
	signs []*types.Signature

	vars map[types.Object]*variable

	skipNext bool
}

func (v *visitor) addParams(t *types.Tuple) {
	for i := 0; i < t.Len(); i++ {
		obj := t.At(i)
		v.vars[obj] = &variable{
			calls:    make(map[string]struct{}),
			usedAs:   make(map[types.Type]struct{}),
			assigned: make(map[*variable]struct{}),
		}
	}
}

func paramType(sign *types.Signature, i int) types.Type {
	params := sign.Params()
	extra := sign.Variadic() && i >= params.Len()-1
	if !extra {
		if i >= params.Len() {
			// builtins with multiple signatures
			return nil
		}
		return params.At(i).Type()
	}
	last := params.At(params.Len() - 1)
	switch x := last.Type().(type) {
	case *types.Slice:
		return x.Elem()
	default:
		return x
	}
}

func (v *visitor) variable(id *ast.Ident) *variable {
	obj := v.ObjectOf(id)
	if vr, e := v.vars[obj]; e {
		return vr
	}
	vr := &variable{
		calls:    make(map[string]struct{}),
		usedAs:   make(map[types.Type]struct{}),
		assigned: make(map[*variable]struct{}),
	}
	v.vars[obj] = vr
	return vr
}

func (v *visitor) addUsed(id *ast.Ident, as types.Type) {
	if as == nil {
		return
	}
	vr := v.variable(id)
	vr.usedAs[as.Underlying()] = struct{}{}
}

func (v *visitor) addAssign(to, from *ast.Ident) {
	pto := v.variable(to)
	pfrom := v.variable(from)
	pfrom.assigned[pto] = struct{}{}
}

func (v *visitor) discard(e ast.Expr) {
	id, ok := e.(*ast.Ident)
	if !ok {
		return
	}
	vr := v.variable(id)
	vr.discard = true
}

func (v *visitor) Visit(node ast.Node) ast.Visitor {
	if v.skipNext {
		v.skipNext = false
		return nil
	}
	var sign *types.Signature
	switch x := node.(type) {
	case *ast.FuncLit:
		sign = v.Types[x].Type.(*types.Signature)
		if implementsIface(sign) {
			return nil
		}
		v.addParams(sign.Params())
	case *ast.FuncDecl:
		sign = v.Defs[x.Name].Type().(*types.Signature)
		if implementsIface(sign) {
			return nil
		}
		v.addParams(sign.Params())
	case *ast.SelectorExpr:
		v.discard(x.X)
	case *ast.UnaryExpr:
		v.discard(x.X)
	case *ast.BinaryExpr:
		v.discard(x.X)
		v.discard(x.Y)
	case *ast.IndexExpr:
		v.discard(x.X)
	case *ast.IncDecStmt:
		v.discard(x.X)
	case *ast.AssignStmt:
		v.onAssign(x)
	case *ast.CallExpr:
		v.onCall(x)
	case nil:
		top := v.signs[len(v.signs)-1]
		if top != nil {
			v.funcEnded(top)
		}
		v.signs = v.signs[:len(v.signs)-1]
	}
	if node != nil {
		v.signs = append(v.signs, sign)
	}
	return v
}

func funcSignature(t types.Type) *types.Signature {
	switch x := t.(type) {
	case *types.Signature:
		return x
	case *types.Named:
		return funcSignature(x.Underlying())
	default:
		return nil
	}
}

func (v *visitor) onAssign(as *ast.AssignStmt) {
	for i, e := range as.Rhs {
		id, ok := e.(*ast.Ident)
		if !ok {
			continue
		}
		left := as.Lhs[i]
		v.addUsed(id, v.Types[left].Type)
		if lid, ok := left.(*ast.Ident); ok {
			v.addAssign(lid, id)
		}
	}
}

func (v *visitor) onCall(ce *ast.CallExpr) {
	switch y := ce.Fun.(type) {
	case *ast.Ident:
		v.skipNext = true
	case *ast.SelectorExpr:
		if _, ok := y.X.(*ast.Ident); ok {
			v.skipNext = true
		}
	}
	sign := funcSignature(v.Types[ce.Fun].Type)
	if sign == nil {
		return
	}
	for i, e := range ce.Args {
		if id, ok := e.(*ast.Ident); ok {
			v.addUsed(id, paramType(sign, i))
		}
	}
	sel, ok := ce.Fun.(*ast.SelectorExpr)
	if !ok {
		return
	}
	left, ok := sel.X.(*ast.Ident)
	if !ok {
		return
	}
	vr := v.variable(left)
	vr.calls[sel.Sel.Name] = struct{}{}
	return
}

func (v *visitor) funcEnded(sign *types.Signature) {
	params := sign.Params()
	for i := 0; i < params.Len(); i++ {
		obj := params.At(i)
		vr := v.vars[obj]
		v.evalParam(obj, vr)
	}
}

func (v *visitor) evalParam(obj types.Object, vr *variable) {
	if vr.discard {
		return
	}
	ifname, iftype := interfaceMatching(obj, vr)
	if ifname == "" {
		return
	}
	t := obj.Type()
	if _, haveIface := t.Underlying().(*types.Interface); haveIface {
		if ifname == t.String() {
			return
		}
		have := funcMapString(doMethoderType(t))
		if have == iftype {
			return
		}
	}
	pos := v.fset.Position(obj.Pos())
	fname := pos.Filename
	if fname[0] == '/' {
		fname = filepath.Join(v.Pkg.Path(), filepath.Base(fname))
	}
	pname := v.Pkg.Name()
	if strings.HasPrefix(ifname, pname+".") {
		ifname = ifname[len(pname)+1:]
	}
	fmt.Fprintf(v.w, "%s:%d:%d: %s can be %s\n",
		fname, pos.Line, pos.Column, obj.Name(), ifname)
}
<|endoftext|>


<commit_before>package main

import (
    "bufio"
    "crypto/rand"
    "flag"
    "fmt"
    "os"
    "os/exec"
    "strings"
)

type Control struct {
    cmds chan *exec.Cmd
    stop chan string
}

type Pod struct {
    name string
    container string
    color int
}

var ctx *string
var width int

func colorize(s string, c int) string {
    return fmt.Sprintf("\033[38;5;%dm%s\033[0m", c, s)
}

func randomColor() int {
    r := make([]byte, 1)
    l, _ := rand.Read(r)
    if l == len(r) {
        return int(r[0]) % 193 + 30
    }
    return 4
}

func (p *Pod) Name() string {
    return colorize(p.name, p.color)
}

func (p *Pod) WideName() string {
    return colorize(fmt.Sprintf("%-[2]*[1]s", p.name, width), p.color)
}

func (p *Pod) Subscribe(ctrl *Control, log chan string) {
    fmt.Println("Subscribed to", p.Name())

    cmd := kubeExec("log", "--tail", "10", "--follow", p.name, p.container)
    ctrl.cmds <- cmd

    stdout, _ := cmd.StdoutPipe()
    scanner := bufio.NewScanner(stdout)

    go func() {
        for scanner.Scan() {
            log <- fmt.Sprintf("[%s] %s", p.WideName(), scanner.Text())
        }
    }()

    cmd.Start()
    cmd.Wait()
    ctrl.stop <- p.Name()
}

func kubeExec(args ...string) *exec.Cmd {
    if len(*ctx) > 0 {
        args = append(args, "--context", *ctx)
    }
    cmd := exec.Command("kubectl", args...)
    return cmd
}

func pods(selector *string) []*Pod {
    jsp := "jsonpath={range .items[*]}{.metadata.name} {.spec.containers[0].name}{\"\\n\"}{end}"
    cmd := kubeExec("get", "pod", "--output", jsp, "--selector", *selector)
    out, err := cmd.CombinedOutput()
    if err != nil {
        fmt.Printf("kubectl error: %s\n", err)
    }
    kpods := strings.Split(strings.Trim(string(out), " \n"), "\n")

    width = 0
    pods := make([]*Pod, 0)

    for _, p := range kpods {
        s := strings.SplitN(p, " ", 2)
        l := len(s[0])
        if l > width {
            width = l
        }
        pods = append(pods, &Pod{name: s[0], container: s[1], color: randomColor()})
    }

    return pods
}

func StopHandler(ctrl *Control) {
    name := <-ctrl.stop
    fmt.Println("Child process terminated:", name)
    for cmd := range ctrl.cmds {
        cmd.Process.Kill()
        cmd.Wait()
        if len(ctrl.cmds) == 0 {
            break
        }
    }
    os.Exit(0)
}

func main() {
    ctx = flag.String("context", "", "The name of the kubeconfig context to use")
    selector := flag.String("l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.")
    flag.Parse()

    pods := pods(selector)
    log := make(chan string)
    ctrl := &Control{cmds: make(chan *exec.Cmd, len(pods)), stop: make(chan string)}

    for _, pod := range pods {
        go pod.Subscribe(ctrl, log)
    }

    go StopHandler(ctrl)

    for {
        fmt.Println(<-log)
    }
}
<commit_msg>go: now exit upon kubectl error<commit_after>package main

import (
    "bufio"
    "crypto/rand"
    "flag"
    "fmt"
    "os"
    "os/exec"
    "strings"
)

type Control struct {
    cmds chan *exec.Cmd
    stop chan string
}

type Pod struct {
    name string
    container string
    color int
}

var ctx *string
var width int

func colorize(s string, c int) string {
    return fmt.Sprintf("\033[38;5;%dm%s\033[0m", c, s)
}

func randomColor() int {
    r := make([]byte, 1)
    l, _ := rand.Read(r)
    if l == len(r) {
        return int(r[0]) % 193 + 30
    }
    return 4
}

func (p *Pod) Name() string {
    return colorize(p.name, p.color)
}

func (p *Pod) WideName() string {
    return colorize(fmt.Sprintf("%-[2]*[1]s", p.name, width), p.color)
}

func (p *Pod) Subscribe(ctrl *Control, log chan string) {
    fmt.Println("Subscribed to", p.Name())

    cmd := kubeExec("log", "--tail", "10", "--follow", p.name, p.container)
    ctrl.cmds <- cmd

    stdout, _ := cmd.StdoutPipe()
    scanner := bufio.NewScanner(stdout)

    go func() {
        for scanner.Scan() {
            log <- fmt.Sprintf("[%s] %s", p.WideName(), scanner.Text())
        }
    }()

    cmd.Start()
    cmd.Wait()
    ctrl.stop <- p.Name()
}

func kubeExec(args ...string) *exec.Cmd {
    if len(*ctx) > 0 {
        args = append(args, "--context", *ctx)
    }
    cmd := exec.Command("kubectl", args...)
    return cmd
}

func pods(selector *string) []*Pod {
    jsp := "jsonpath={range .items[*]}{.metadata.name} {.spec.containers[0].name}{\"\\n\"}{end}"
    cmd := kubeExec("get", "pod", "--output", jsp, "--selector", *selector)
    out, err := cmd.CombinedOutput()
    if err != nil {
        fmt.Printf("kubectl (%s): %s", err, string(out))
        os.Exit(1)
    }
    kpods := strings.Split(strings.Trim(string(out), " \n"), "\n")

    width = 0
    pods := make([]*Pod, 0)

    for _, p := range kpods {
        s := strings.SplitN(p, " ", 2)
        l := len(s[0])
        if l > width {
            width = l
        }
        pods = append(pods, &Pod{name: s[0], container: s[1], color: randomColor()})
    }

    return pods
}

func StopHandler(ctrl *Control) {
    name := <-ctrl.stop
    fmt.Println("Child process terminated:", name)
    for cmd := range ctrl.cmds {
        cmd.Process.Kill()
        cmd.Wait()
        if len(ctrl.cmds) == 0 {
            break
        }
    }
    os.Exit(0)
}

func main() {
    ctx = flag.String("context", "", "The name of the kubeconfig context to use")
    selector := flag.String("l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.")
    flag.Parse()

    pods := pods(selector)
    log := make(chan string)
    ctrl := &Control{cmds: make(chan *exec.Cmd, len(pods)), stop: make(chan string)}

    for _, pod := range pods {
        go pod.Subscribe(ctrl, log)
    }

    go StopHandler(ctrl)

    for {
        fmt.Println(<-log)
    }
}
<|endoftext|>