<commit_before>package main

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func validateEndpointForConfig(endpoint string) error {
	url, err := url.Parse(endpoint)
	if err != nil {
		return err
	}
	if url.Scheme != "http" && url.Scheme != "https" {
		return errors.New("The endpoint URL should start with http:// or https://")
	}
	if url.Host == "" {
		return errors.New("The endpoint URL should have a hostname")
	}
	return nil
}

func validateAccountForConfig(c *app.Context, name string) (err error) {
	_, err = c.Client().GetAccount(name)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such account %s - check your typing and specify --yubikey if necessary", name)
		}
		return err
	}
	return
}

func validateGroupForConfig(c *app.Context, name string) (err error) {
	// we can't just use with.Group because it expects NextArg() to be the account name - there's no way to pass one in.
	groupName := lib.ParseGroupName(name, c.Config().GetGroup())
	_, err = c.Client().GetGroup(groupName)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such group %v - check your typing and specify --yubikey if necessary", groupName)
		}
		return err
	}
	return
}

func validateConfigValue(c *app.Context, varname string, value string) error {
	if c.Bool("force") {
		return nil
	}
	switch varname {
	case "endpoint", "api-endpoint", "billing-endpoint", "spp-endpoint", "auth-endpoint":
		return validateEndpointForConfig(value)
	case "account":
		return validateAccountForConfig(c, value)
	case "group":
		return validateGroupForConfig(c, value)
	case "debug-level":
		_, err := strconv.ParseUint(value, 10, 32)
		if err != nil {
			return errors.New("debug-level must be an integer")
		}
	}
	return nil
}

func init() {
	commands = append(commands, cli.Command{
		Name:      "config",
		Usage:     "manage the bytemark client's configuration",
		UsageText: "config [ set | unset ]",
		Description: `view and manipulate the bytemark-client configuration

When invoked with no subcommand, outputs the current values of all variables and what source they were derived from.
The set and unset subcommands can be used to set and unset such variables.

    Available variables:
        account - the default account, used when you do not explicitly state an account - defaults to the same as your user name
        token - the token used for authentication
        user - the user that you log in as by default
        group - the default group, used when you do not explicitly state a group (defaults to 'default')

        debug-level - the default debug level. Set to 0 unless you like lots of output.
	api-endpoint - the endpoint for domains (among other things?)
        auth-endpoint - the endpoint to authenticate to. https://auth.bytemark.co.uk is the default.
        endpoint - the brain endpoint to connect to. https://uk0.bigv.io is the default.
        billing-endpoint - the billing API endpoint to connect to. https://bmbilling.bytemark.co.uk is the default.
        spp-endpoint - the SPP endpoint to use. https://spp-submissions.bytemark.co.uk is the default.`,
		Subcommands: []cli.Command{
			{
				Name:        "set",
				UsageText:   "bytemark config set <variable> <value>",
				Usage:       "sets a bytemark client configuration request",
				Description: "Sets the named variable to the given value. See `bytemark help config` for which variables are available",
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "force",
						Usage: "Don't run any validation checks against the value",
					},
				},
				Action: app.With(func(ctx *app.Context) error {
					varname, err := ctx.NextArg()
					if err != nil {
						return err
					}
					varname = strings.ToLower(varname)

					if !util.IsConfigVar(varname) {
						return ctx.Help(fmt.Sprintf("%s is not a valid variable name", varname))
					}

					oldVar, err := ctx.Config().GetV(varname)
					if err != nil {
						return err
					}

					value, err := ctx.NextArg()
					if err != nil {
						return err
					}

					if varname == "account" || varname == "group" {
						err = with.Auth(ctx)
						if err != nil {
							return err
						}
					}

					err = validateConfigValue(ctx, varname, value)
					if err != nil {
						return err
					}

					err = ctx.Config().SetPersistent(varname, value, "CMD set")
					if err != nil {
						return err
					}

					if oldVar.Source == "config" {
						log.Logf("%s has been changed.\r\nOld value: %s\r\nNew value: %s\r\n", varname, oldVar.Value, ctx.Config().GetIgnoreErr(varname))
					} else {
						log.Logf("%s has been set. \r\nNew value: %s\r\n", varname, ctx.Config().GetIgnoreErr(varname))
					}
					return nil
				}),
			}, {
				Name:        "unset",
				UsageText:   "bytemark config unset <variable>",
				Usage:       "unsets a bytemark client configuration option",
				Description: "Unsets the named variable.",
				Action: app.With(func(ctx *app.Context) error {
					varname, err := ctx.NextArg()
					if err != nil {
						return err
					}
					varname = strings.ToLower(varname)
					return ctx.Config().Unset(varname)
				}),
			},
		},
		Action: app.With(func(ctx *app.Context) (err error) {
			/* TODO(telyn): put this back. Phil - if you see this, I hecked up.
			if ctx.Bool("help") {
				if ccw, ok := ctx.Context.(cliContextWrapper); ok {
					err = cli.ShowSubcommandHelp(ccw.Context)
					return
				}
			}*/
			vars, err := ctx.Config().GetAll()
			if err != nil {
				return
			}
			for _, v := range vars {
				log.Logf("%s\t: '%s' (%s)\r\n", v.Name, v.Value, v.Source)
			}
			return
		}),
	})
}
<commit_msg>That code didn't actually do anything anyway<commit_after>package main

import (
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/app/with"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
)

func validateEndpointForConfig(endpoint string) error {
	url, err := url.Parse(endpoint)
	if err != nil {
		return err
	}
	if url.Scheme != "http" && url.Scheme != "https" {
		return errors.New("The endpoint URL should start with http:// or https://")
	}
	if url.Host == "" {
		return errors.New("The endpoint URL should have a hostname")
	}
	return nil
}

func validateAccountForConfig(c *app.Context, name string) (err error) {
	_, err = c.Client().GetAccount(name)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such account %s - check your typing and specify --yubikey if necessary", name)
		}
		return err
	}
	return
}

func validateGroupForConfig(c *app.Context, name string) (err error) {
	// we can't just use with.Group because it expects NextArg() to be the account name - there's no way to pass one in.
	groupName := lib.ParseGroupName(name, c.Config().GetGroup())
	_, err = c.Client().GetGroup(groupName)
	if err != nil {
		if _, ok := err.(lib.NotFoundError); ok {
			return fmt.Errorf("No such group %v - check your typing and specify --yubikey if necessary", groupName)
		}
		return err
	}
	return
}

func validateConfigValue(c *app.Context, varname string, value string) error {
	if c.Bool("force") {
		return nil
	}
	switch varname {
	case "endpoint", "api-endpoint", "billing-endpoint", "spp-endpoint", "auth-endpoint":
		return validateEndpointForConfig(value)
	case "account":
		return validateAccountForConfig(c, value)
	case "group":
		return validateGroupForConfig(c, value)
	case "debug-level":
		_, err := strconv.ParseUint(value, 10, 32)
		if err != nil {
			return errors.New("debug-level must be an integer")
		}
	}
	return nil
}

func init() {
	commands = append(commands, cli.Command{
		Name:      "config",
		Usage:     "manage the bytemark client's configuration",
		UsageText: "config [ set | unset ]",
		Description: `view and manipulate the bytemark-client configuration

When invoked with no subcommand, outputs the current values of all variables and what source they were derived from.
The set and unset subcommands can be used to set and unset such variables.

    Available variables:
        account - the default account, used when you do not explicitly state an account - defaults to the same as your user name
        token - the token used for authentication
        user - the user that you log in as by default
        group - the default group, used when you do not explicitly state a group (defaults to 'default')

        debug-level - the default debug level. Set to 0 unless you like lots of output.
	api-endpoint - the endpoint for domains (among other things?)
        auth-endpoint - the endpoint to authenticate to. https://auth.bytemark.co.uk is the default.
        endpoint - the brain endpoint to connect to. https://uk0.bigv.io is the default.
        billing-endpoint - the billing API endpoint to connect to. https://bmbilling.bytemark.co.uk is the default.
        spp-endpoint - the SPP endpoint to use. https://spp-submissions.bytemark.co.uk is the default.`,
		Subcommands: []cli.Command{
			{
				Name:        "set",
				UsageText:   "bytemark config set <variable> <value>",
				Usage:       "sets a bytemark client configuration request",
				Description: "Sets the named variable to the given value. See `bytemark help config` for which variables are available",
				Flags: []cli.Flag{
					cli.BoolFlag{
						Name:  "force",
						Usage: "Don't run any validation checks against the value",
					},
				},
				Action: app.With(func(ctx *app.Context) error {
					varname, err := ctx.NextArg()
					if err != nil {
						return err
					}
					varname = strings.ToLower(varname)

					if !util.IsConfigVar(varname) {
						return ctx.Help(fmt.Sprintf("%s is not a valid variable name", varname))
					}

					oldVar, err := ctx.Config().GetV(varname)
					if err != nil {
						return err
					}

					value, err := ctx.NextArg()
					if err != nil {
						return err
					}

					if varname == "account" || varname == "group" {
						err = with.Auth(ctx)
						if err != nil {
							return err
						}
					}

					err = validateConfigValue(ctx, varname, value)
					if err != nil {
						return err
					}

					err = ctx.Config().SetPersistent(varname, value, "CMD set")
					if err != nil {
						return err
					}

					if oldVar.Source == "config" {
						log.Logf("%s has been changed.\r\nOld value: %s\r\nNew value: %s\r\n", varname, oldVar.Value, ctx.Config().GetIgnoreErr(varname))
					} else {
						log.Logf("%s has been set. \r\nNew value: %s\r\n", varname, ctx.Config().GetIgnoreErr(varname))
					}
					return nil
				}),
			}, {
				Name:        "unset",
				UsageText:   "bytemark config unset <variable>",
				Usage:       "unsets a bytemark client configuration option",
				Description: "Unsets the named variable.",
				Action: app.With(func(ctx *app.Context) error {
					varname, err := ctx.NextArg()
					if err != nil {
						return err
					}
					varname = strings.ToLower(varname)
					return ctx.Config().Unset(varname)
				}),
			},
		},
		Action: app.With(func(ctx *app.Context) (err error) {
			vars, err := ctx.Config().GetAll()
			if err != nil {
				return
			}
			for _, v := range vars {
				log.Logf("%s\t: '%s' (%s)\r\n", v.Name, v.Value, v.Source)
			}
			return
		}),
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"flag"
	"log"
	"time"

	"github.com/knative/pkg/configmap"

	"github.com/knative/pkg/controller"
	"github.com/knative/serving/pkg/logging"
	"github.com/knative/serving/pkg/reconciler"

	"github.com/knative/serving/pkg/system"

	vpa "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
	vpainformers "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/informers/externalversions"
	"k8s.io/client-go/dynamic"
	kubeinformers "k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	cachingclientset "github.com/knative/caching/pkg/client/clientset/versioned"
	cachinginformers "github.com/knative/caching/pkg/client/informers/externalversions"
	sharedclientset "github.com/knative/pkg/client/clientset/versioned"
	sharedinformers "github.com/knative/pkg/client/informers/externalversions"
	"github.com/knative/pkg/signals"
	clientset "github.com/knative/serving/pkg/client/clientset/versioned"
	informers "github.com/knative/serving/pkg/client/informers/externalversions"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/configuration"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/revision"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/route"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/service"
)

const (
	threadsPerController = 2
	logLevelKey          = "controller"
)

var (
	masterURL  = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
	kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
)

func main() {
	flag.Parse()
	loggingConfigMap, err := configmap.Load("/etc/config-logging")
	if err != nil {
		log.Fatalf("Error loading logging configuration: %v", err)
	}
	loggingConfig, err := logging.NewConfigFromMap(loggingConfigMap)
	if err != nil {
		log.Fatalf("Error parsing logging configuration: %v", err)
	}
	logger, atomicLevel := logging.NewLoggerFromConfig(loggingConfig, logLevelKey)
	defer logger.Sync()

	// set up signals so we handle the first shutdown signal gracefully
	stopCh := signals.SetupSignalHandler()

	cfg, err := clientcmd.BuildConfigFromFlags(*masterURL, *kubeconfig)
	if err != nil {
		logger.Fatalf("Error building kubeconfig: %v", err)
	}

	kubeClient, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building kubernetes clientset: %v", err)
	}

	sharedClient, err := sharedclientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building shared clientset: %v", err)
	}

	servingClient, err := clientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building serving clientset: %v", err)
	}

	dynamicClient, err := dynamic.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building build clientset: %v", err)
	}

	cachingClient, err := cachingclientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building caching clientset: %v", err)
	}

	vpaClient, err := vpa.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building VPA clientset: %v", err)
	}

	configMapWatcher := configmap.NewInformedWatcher(kubeClient, system.Namespace)

	opt := reconciler.Options{
		KubeClientSet:    kubeClient,
		SharedClientSet:  sharedClient,
		ServingClientSet: servingClient,
		CachingClientSet: cachingClient,
		DynamicClientSet: dynamicClient,
		ConfigMapWatcher: configMapWatcher,
		Logger:           logger,
		ResyncPeriod:     time.Second * 30,
		StopChannel:      stopCh,
	}

	kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, opt.ResyncPeriod)
	sharedInformerFactory := sharedinformers.NewSharedInformerFactory(sharedClient, opt.ResyncPeriod)
	servingInformerFactory := informers.NewSharedInformerFactory(servingClient, opt.ResyncPeriod)
	cachingInformerFactory := cachinginformers.NewSharedInformerFactory(cachingClient, opt.ResyncPeriod)
	vpaInformerFactory := vpainformers.NewSharedInformerFactory(vpaClient, opt.ResyncPeriod)
	buildInformerFactory := revision.KResourceTypedInformerFactory(opt)

	serviceInformer := servingInformerFactory.Serving().V1alpha1().Services()
	routeInformer := servingInformerFactory.Serving().V1alpha1().Routes()
	configurationInformer := servingInformerFactory.Serving().V1alpha1().Configurations()
	revisionInformer := servingInformerFactory.Serving().V1alpha1().Revisions()
	kpaInformer := servingInformerFactory.Autoscaling().V1alpha1().PodAutoscalers()
	deploymentInformer := kubeInformerFactory.Apps().V1().Deployments()
	coreServiceInformer := kubeInformerFactory.Core().V1().Services()
	endpointsInformer := kubeInformerFactory.Core().V1().Endpoints()
	configMapInformer := kubeInformerFactory.Core().V1().ConfigMaps()
	virtualServiceInformer := sharedInformerFactory.Networking().V1alpha3().VirtualServices()
	imageInformer := cachingInformerFactory.Caching().V1alpha1().Images()
	vpaInformer := vpaInformerFactory.Poc().V1alpha1().VerticalPodAutoscalers()

	// Build all of our controllers, with the clients constructed above.
	// Add new controllers to this array.
	controllers := []*controller.Impl{
		configuration.NewController(
			opt,
			configurationInformer,
			revisionInformer,
		),
		revision.NewController(
			opt,
			vpaClient,
			revisionInformer,
			kpaInformer,
			imageInformer,
			deploymentInformer,
			coreServiceInformer,
			endpointsInformer,
			configMapInformer,
			vpaInformer,
			buildInformerFactory,
		),
		route.NewController(
			opt,
			routeInformer,
			configurationInformer,
			revisionInformer,
			coreServiceInformer,
			virtualServiceInformer,
		),
		service.NewController(
			opt,
			serviceInformer,
			configurationInformer,
			routeInformer,
		),
	}

	// Watch the logging config map and dynamically update logging levels.
	configMapWatcher.Watch(logging.ConfigName, logging.UpdateLevelFromConfigMap(logger, atomicLevel, logLevelKey))

	// These are non-blocking.
	kubeInformerFactory.Start(stopCh)
	sharedInformerFactory.Start(stopCh)
	servingInformerFactory.Start(stopCh)
	cachingInformerFactory.Start(stopCh)
	vpaInformerFactory.Start(stopCh)
	if err := configMapWatcher.Start(stopCh); err != nil {
		logger.Fatalf("failed to start configuration manager: %v", err)
	}

	// Wait for the caches to be synced before starting controllers.
	logger.Info("Waiting for informer caches to sync")
	for i, synced := range []cache.InformerSynced{
		serviceInformer.Informer().HasSynced,
		routeInformer.Informer().HasSynced,
		configurationInformer.Informer().HasSynced,
		revisionInformer.Informer().HasSynced,
		kpaInformer.Informer().HasSynced,
		imageInformer.Informer().HasSynced,
		deploymentInformer.Informer().HasSynced,
		coreServiceInformer.Informer().HasSynced,
		endpointsInformer.Informer().HasSynced,
		configMapInformer.Informer().HasSynced,
		virtualServiceInformer.Informer().HasSynced,
	} {
		if ok := cache.WaitForCacheSync(stopCh, synced); !ok {
			logger.Fatalf("failed to wait for cache at index %v to sync", i)
		}
	}

	// Start all of the controllers.
	for _, ctrlr := range controllers {
		go func(ctrlr *controller.Impl) {
			// We don't expect this to return until stop is called,
			// but if it does, propagate it back.
			if runErr := ctrlr.Run(threadsPerController, stopCh); runErr != nil {
				logger.Fatalf("Error running controller: %v", runErr)
			}
		}(ctrlr)
	}

	<-stopCh
}
<commit_msg>Bump the resync period enough to shake out issues in e2e. (#2133)<commit_after>/*
Copyright 2018 The Knative Authors

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

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

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

package main

import (
	"flag"
	"log"
	"time"

	"github.com/knative/pkg/configmap"

	"github.com/knative/pkg/controller"
	"github.com/knative/serving/pkg/logging"
	"github.com/knative/serving/pkg/reconciler"

	"github.com/knative/serving/pkg/system"

	vpa "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/clientset/versioned"
	vpainformers "k8s.io/autoscaler/vertical-pod-autoscaler/pkg/client/informers/externalversions"
	"k8s.io/client-go/dynamic"
	kubeinformers "k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"

	cachingclientset "github.com/knative/caching/pkg/client/clientset/versioned"
	cachinginformers "github.com/knative/caching/pkg/client/informers/externalversions"
	sharedclientset "github.com/knative/pkg/client/clientset/versioned"
	sharedinformers "github.com/knative/pkg/client/informers/externalversions"
	"github.com/knative/pkg/signals"
	clientset "github.com/knative/serving/pkg/client/clientset/versioned"
	informers "github.com/knative/serving/pkg/client/informers/externalversions"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/configuration"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/revision"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/route"
	"github.com/knative/serving/pkg/reconciler/v1alpha1/service"
)

const (
	threadsPerController = 2
	logLevelKey          = "controller"
)

var (
	masterURL  = flag.String("master", "", "The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster.")
	kubeconfig = flag.String("kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
)

func main() {
	flag.Parse()
	loggingConfigMap, err := configmap.Load("/etc/config-logging")
	if err != nil {
		log.Fatalf("Error loading logging configuration: %v", err)
	}
	loggingConfig, err := logging.NewConfigFromMap(loggingConfigMap)
	if err != nil {
		log.Fatalf("Error parsing logging configuration: %v", err)
	}
	logger, atomicLevel := logging.NewLoggerFromConfig(loggingConfig, logLevelKey)
	defer logger.Sync()

	// set up signals so we handle the first shutdown signal gracefully
	stopCh := signals.SetupSignalHandler()

	cfg, err := clientcmd.BuildConfigFromFlags(*masterURL, *kubeconfig)
	if err != nil {
		logger.Fatalf("Error building kubeconfig: %v", err)
	}

	kubeClient, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building kubernetes clientset: %v", err)
	}

	sharedClient, err := sharedclientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building shared clientset: %v", err)
	}

	servingClient, err := clientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building serving clientset: %v", err)
	}

	dynamicClient, err := dynamic.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building build clientset: %v", err)
	}

	cachingClient, err := cachingclientset.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building caching clientset: %v", err)
	}

	vpaClient, err := vpa.NewForConfig(cfg)
	if err != nil {
		logger.Fatalf("Error building VPA clientset: %v", err)
	}

	configMapWatcher := configmap.NewInformedWatcher(kubeClient, system.Namespace)

	opt := reconciler.Options{
		KubeClientSet:    kubeClient,
		SharedClientSet:  sharedClient,
		ServingClientSet: servingClient,
		CachingClientSet: cachingClient,
		DynamicClientSet: dynamicClient,
		ConfigMapWatcher: configMapWatcher,
		Logger:           logger,
		ResyncPeriod:     10 * time.Hour, // Based on controller-runtime default.
		StopChannel:      stopCh,
	}

	kubeInformerFactory := kubeinformers.NewSharedInformerFactory(kubeClient, opt.ResyncPeriod)
	sharedInformerFactory := sharedinformers.NewSharedInformerFactory(sharedClient, opt.ResyncPeriod)
	servingInformerFactory := informers.NewSharedInformerFactory(servingClient, opt.ResyncPeriod)
	cachingInformerFactory := cachinginformers.NewSharedInformerFactory(cachingClient, opt.ResyncPeriod)
	vpaInformerFactory := vpainformers.NewSharedInformerFactory(vpaClient, opt.ResyncPeriod)
	buildInformerFactory := revision.KResourceTypedInformerFactory(opt)

	serviceInformer := servingInformerFactory.Serving().V1alpha1().Services()
	routeInformer := servingInformerFactory.Serving().V1alpha1().Routes()
	configurationInformer := servingInformerFactory.Serving().V1alpha1().Configurations()
	revisionInformer := servingInformerFactory.Serving().V1alpha1().Revisions()
	kpaInformer := servingInformerFactory.Autoscaling().V1alpha1().PodAutoscalers()
	deploymentInformer := kubeInformerFactory.Apps().V1().Deployments()
	coreServiceInformer := kubeInformerFactory.Core().V1().Services()
	endpointsInformer := kubeInformerFactory.Core().V1().Endpoints()
	configMapInformer := kubeInformerFactory.Core().V1().ConfigMaps()
	virtualServiceInformer := sharedInformerFactory.Networking().V1alpha3().VirtualServices()
	imageInformer := cachingInformerFactory.Caching().V1alpha1().Images()
	vpaInformer := vpaInformerFactory.Poc().V1alpha1().VerticalPodAutoscalers()

	// Build all of our controllers, with the clients constructed above.
	// Add new controllers to this array.
	controllers := []*controller.Impl{
		configuration.NewController(
			opt,
			configurationInformer,
			revisionInformer,
		),
		revision.NewController(
			opt,
			vpaClient,
			revisionInformer,
			kpaInformer,
			imageInformer,
			deploymentInformer,
			coreServiceInformer,
			endpointsInformer,
			configMapInformer,
			vpaInformer,
			buildInformerFactory,
		),
		route.NewController(
			opt,
			routeInformer,
			configurationInformer,
			revisionInformer,
			coreServiceInformer,
			virtualServiceInformer,
		),
		service.NewController(
			opt,
			serviceInformer,
			configurationInformer,
			routeInformer,
		),
	}

	// Watch the logging config map and dynamically update logging levels.
	configMapWatcher.Watch(logging.ConfigName, logging.UpdateLevelFromConfigMap(logger, atomicLevel, logLevelKey))

	// These are non-blocking.
	kubeInformerFactory.Start(stopCh)
	sharedInformerFactory.Start(stopCh)
	servingInformerFactory.Start(stopCh)
	cachingInformerFactory.Start(stopCh)
	vpaInformerFactory.Start(stopCh)
	if err := configMapWatcher.Start(stopCh); err != nil {
		logger.Fatalf("failed to start configuration manager: %v", err)
	}

	// Wait for the caches to be synced before starting controllers.
	logger.Info("Waiting for informer caches to sync")
	for i, synced := range []cache.InformerSynced{
		serviceInformer.Informer().HasSynced,
		routeInformer.Informer().HasSynced,
		configurationInformer.Informer().HasSynced,
		revisionInformer.Informer().HasSynced,
		kpaInformer.Informer().HasSynced,
		imageInformer.Informer().HasSynced,
		deploymentInformer.Informer().HasSynced,
		coreServiceInformer.Informer().HasSynced,
		endpointsInformer.Informer().HasSynced,
		configMapInformer.Informer().HasSynced,
		virtualServiceInformer.Informer().HasSynced,
	} {
		if ok := cache.WaitForCacheSync(stopCh, synced); !ok {
			logger.Fatalf("failed to wait for cache at index %v to sync", i)
		}
	}

	// Start all of the controllers.
	for _, ctrlr := range controllers {
		go func(ctrlr *controller.Impl) {
			// We don't expect this to return until stop is called,
			// but if it does, propagate it back.
			if runErr := ctrlr.Run(threadsPerController, stopCh); runErr != nil {
				logger.Fatalf("Error running controller: %v", runErr)
			}
		}(ctrlr)
	}

	<-stopCh
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
	"regexp"

	"github.com/gruntwork-io/terragrunt/config"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/locks"
	"github.com/gruntwork-io/terragrunt/remote"
	"github.com/gruntwork-io/terragrunt/shell"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/urfave/cli"
)

// Since Terragrunt is just a thin wrapper for Terraform, and we don't want to repeat every single Terraform command
// in its definition, we don't quite fit into the model of any Go CLI library. Fortunately, urfave/cli allows us to
// override the whole template used for the Usage Text.
const CUSTOM_USAGE_TEXT = `DESCRIPTION:
   {{.Name}} - {{.UsageText}}

USAGE:
   {{.Usage}}

COMMANDS:
   apply                Acquire a lock and run 'terraform apply'
   destroy              Acquire a lock and run 'terraform destroy'
   release-lock         Release a lock that is left over from some previous command
   *                    Terragrunt forwards all other commands directly to Terraform
{{if .VisibleFlags}}
GLOBAL OPTIONS:
   {{range .VisibleFlags}}{{.}}
   {{end}}{{end}}
VERSION:
   {{.Version}}{{if len .Authors}}

AUTHOR(S):
   {{range .Authors}}{{.}}{{end}}
   {{end}}
`

var MODULE_REGEX = regexp.MustCompile(`module ".+"`)

const TERRAFORM_EXTENSION_GLOB = "*.tf"

// Create the Terragrunt CLI App
func CreateTerragruntCli(version string) *cli.App {
	cli.AppHelpTemplate = CUSTOM_USAGE_TEXT

	app := cli.NewApp()

	app.Name = "terragrunt"
	app.Author = "Gruntwork <www.gruntwork.io>"
	app.Version = version
	app.Action = runApp
	app.Usage = "terragrunt <COMMAND>"
	app.UsageText = `Terragrunt is a thin wrapper for [Terraform](https://www.terraform.io/) that supports locking
   via Amazon's DynamoDB and enforces best practices. Terragrunt forwards almost all commands, arguments, and options
   directly to Terraform, using whatever version of Terraform you already have installed. However, before running
   Terraform, Terragrunt will ensure your remote state is configured according to the settings in the .terragrunt file.
   Moreover, for the apply and destroy commands, Terragrunt will first try to acquire a lock using DynamoDB. For
   documentation, see https://github.com/gruntwork-io/terragrunt/.`

	var defaultConfigFilePath = config.ConfigFilePath
	if os.Getenv("TERRAGRUNT_CONFIG") != "" {
		defaultConfigFilePath = os.Getenv("TERRAGRUNT_CONFIG")
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "terragrunt-config",
			Value: defaultConfigFilePath,
			Usage: ".terragrunt file to use",
		},
	}

	return app
}

// The sole action for the app. It forwards all commands directly to Terraform, enforcing a few best practices along
// the way, such as configuring remote state or acquiring a lock.
func runApp(cliContext *cli.Context) (finalErr error) {
	defer errors.Recover(func(cause error) { finalErr = cause })

	// If someone calls us with no args at all, show the help text and exit
	if !cliContext.Args().Present() {
		cli.ShowAppHelp(cliContext)
		return nil
	}

	conf, err := config.ReadTerragruntConfig(cliContext.String("terragrunt-config"))
	if err != nil {
		return err
	}

	if err := downloadModules(cliContext); err != nil {
		return err
	}

	if conf.RemoteState != nil {
		if err := configureRemoteState(cliContext, conf.RemoteState); err != nil {
			return err
		}
	}

	if conf.Lock == nil {
		util.Logger.Printf("WARNING: you have not configured locking in your .terragrunt file. Concurrent changes to your .tfstate files may cause conflicts!")
		return runTerraformCommand(cliContext)
	}

	return runTerraformCommandWithLock(cliContext, conf.Lock)
}

// A quick sanity check that calls `terraform get` to download modules, if they aren't already downloaded.
func downloadModules(cliContext *cli.Context) error {
	switch cliContext.Args().First() {
	case "apply", "destroy", "graph", "output", "plan", "show", "taint", "untaint", "validate":
		shouldDownload, err := shouldDownloadModules()
		if err != nil {
			return err
		}
		if shouldDownload {
			return shell.RunShellCommand("terraform", "get", "-update")
		}
	}

	return nil
}

// Return true if modules aren't already downloaded and the Terraform templates in this project reference modules.
// Note that to keep the logic in this code very simple, this code ONLY detects the case where you haven't downloaded
// modules at all. Detecting if your downloaded modules are out of date (as opposed to missing entirely) is more
// complicated and not something we handle at the moment.
func shouldDownloadModules() (bool, error) {
	if util.FileExists(".terraform/modules") {
		return false, nil
	}

	return util.Grep(MODULE_REGEX, TERRAFORM_EXTENSION_GLOB)
}

// If the user entered a Terraform command that uses state (e.g. plan, apply), make sure remote state is configured
// before running the command.
func configureRemoteState(cliContext *cli.Context, remoteState *remote.RemoteState) error {
	// We only configure remote state for the commands that use the tfstate files. We do not configure it for
	// commands such as "get" or "version".
	switch cliContext.Args().First() {
	case "apply", "destroy", "graph", "output", "plan", "push", "refresh", "show", "taint", "untaint", "validate":
		return remoteState.ConfigureRemoteState()
	case "remote":
		if cliContext.Args().Get(1) == "config" {
			// Encourage the user to configure remote state by defining it in .terragrunt and letting
			// Terragrunt handle it for them
			return errors.WithStackTrace(DontManuallyConfigureRemoteState)
		} else {
			// The other "terraform remote" commands explicitly push or pull state, so we shouldn't mess
			// with the configuration
			return nil
		}
	}

	return nil
}

// Run the given Terraform command with the given lock (if the command requires locking)
func runTerraformCommandWithLock(cliContext *cli.Context, lock locks.Lock) error {
	switch cliContext.Args().First() {
	case "apply", "destroy":
		return locks.WithLock(lock, func() error { return runTerraformCommand(cliContext) })
	case "release-lock":
		return runReleaseLockCommand(cliContext, lock)
	default:
		return runTerraformCommand(cliContext)
	}
}

// Run the given Terraform command
func runTerraformCommand(cliContext *cli.Context) error {
	return shell.RunShellCommand("terraform", cliContext.Args()...)
}

// Release a lock, prompting the user for confirmation first
func runReleaseLockCommand(cliContext *cli.Context, lock locks.Lock) error {
	proceed, err := shell.PromptUserForYesNo(fmt.Sprintf("Are you sure you want to release %s?", lock))
	if err != nil {
		return err
	}

	if proceed {
		return lock.ReleaseLock()
	} else {
		return nil
	}
}

var DontManuallyConfigureRemoteState = fmt.Errorf("Instead of manually using the 'remote config' command, define your remote state settings in .terragrunt and Terragrunt will automatically configure it for you (and all your team members) next time you run it.")
<commit_msg>Add import command to lock and push state actions<commit_after>package cli

import (
	"fmt"
	"os"
	"regexp"

	"github.com/gruntwork-io/terragrunt/config"
	"github.com/gruntwork-io/terragrunt/errors"
	"github.com/gruntwork-io/terragrunt/locks"
	"github.com/gruntwork-io/terragrunt/remote"
	"github.com/gruntwork-io/terragrunt/shell"
	"github.com/gruntwork-io/terragrunt/util"
	"github.com/urfave/cli"
)

// Since Terragrunt is just a thin wrapper for Terraform, and we don't want to repeat every single Terraform command
// in its definition, we don't quite fit into the model of any Go CLI library. Fortunately, urfave/cli allows us to
// override the whole template used for the Usage Text.
const CUSTOM_USAGE_TEXT = `DESCRIPTION:
   {{.Name}} - {{.UsageText}}

USAGE:
   {{.Usage}}

COMMANDS:
   apply                Acquire a lock and run 'terraform apply'
   destroy              Acquire a lock and run 'terraform destroy'
   import               Acquire a lock and run 'terraform import'
   release-lock         Release a lock that is left over from some previous command
   *                    Terragrunt forwards all other commands directly to Terraform
{{if .VisibleFlags}}
GLOBAL OPTIONS:
   {{range .VisibleFlags}}{{.}}
   {{end}}{{end}}
VERSION:
   {{.Version}}{{if len .Authors}}

AUTHOR(S):
   {{range .Authors}}{{.}}{{end}}
   {{end}}
`

var MODULE_REGEX = regexp.MustCompile(`module ".+"`)

const TERRAFORM_EXTENSION_GLOB = "*.tf"

// Create the Terragrunt CLI App
func CreateTerragruntCli(version string) *cli.App {
	cli.AppHelpTemplate = CUSTOM_USAGE_TEXT

	app := cli.NewApp()

	app.Name = "terragrunt"
	app.Author = "Gruntwork <www.gruntwork.io>"
	app.Version = version
	app.Action = runApp
	app.Usage = "terragrunt <COMMAND>"
	app.UsageText = `Terragrunt is a thin wrapper for [Terraform](https://www.terraform.io/) that supports locking
   via Amazon's DynamoDB and enforces best practices. Terragrunt forwards almost all commands, arguments, and options
   directly to Terraform, using whatever version of Terraform you already have installed. However, before running
   Terraform, Terragrunt will ensure your remote state is configured according to the settings in the .terragrunt file.
   Moreover, for the apply and destroy commands, Terragrunt will first try to acquire a lock using DynamoDB. For
   documentation, see https://github.com/gruntwork-io/terragrunt/.`

	var defaultConfigFilePath = config.ConfigFilePath
	if os.Getenv("TERRAGRUNT_CONFIG") != "" {
		defaultConfigFilePath = os.Getenv("TERRAGRUNT_CONFIG")
	}

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "terragrunt-config",
			Value: defaultConfigFilePath,
			Usage: ".terragrunt file to use",
		},
	}

	return app
}

// The sole action for the app. It forwards all commands directly to Terraform, enforcing a few best practices along
// the way, such as configuring remote state or acquiring a lock.
func runApp(cliContext *cli.Context) (finalErr error) {
	defer errors.Recover(func(cause error) { finalErr = cause })

	// If someone calls us with no args at all, show the help text and exit
	if !cliContext.Args().Present() {
		cli.ShowAppHelp(cliContext)
		return nil
	}

	conf, err := config.ReadTerragruntConfig(cliContext.String("terragrunt-config"))
	if err != nil {
		return err
	}

	if err := downloadModules(cliContext); err != nil {
		return err
	}

	if conf.RemoteState != nil {
		if err := configureRemoteState(cliContext, conf.RemoteState); err != nil {
			return err
		}
	}

	if conf.Lock == nil {
		util.Logger.Printf("WARNING: you have not configured locking in your .terragrunt file. Concurrent changes to your .tfstate files may cause conflicts!")
		return runTerraformCommand(cliContext)
	}

	return runTerraformCommandWithLock(cliContext, conf.Lock)
}

// A quick sanity check that calls `terraform get` to download modules, if they aren't already downloaded.
func downloadModules(cliContext *cli.Context) error {
	switch cliContext.Args().First() {
	case "apply", "destroy", "graph", "output", "plan", "show", "taint", "untaint", "validate":
		shouldDownload, err := shouldDownloadModules()
		if err != nil {
			return err
		}
		if shouldDownload {
			return shell.RunShellCommand("terraform", "get", "-update")
		}
	}

	return nil
}

// Return true if modules aren't already downloaded and the Terraform templates in this project reference modules.
// Note that to keep the logic in this code very simple, this code ONLY detects the case where you haven't downloaded
// modules at all. Detecting if your downloaded modules are out of date (as opposed to missing entirely) is more
// complicated and not something we handle at the moment.
func shouldDownloadModules() (bool, error) {
	if util.FileExists(".terraform/modules") {
		return false, nil
	}

	return util.Grep(MODULE_REGEX, TERRAFORM_EXTENSION_GLOB)
}

// If the user entered a Terraform command that uses state (e.g. plan, apply), make sure remote state is configured
// before running the command.
func configureRemoteState(cliContext *cli.Context, remoteState *remote.RemoteState) error {
	// We only configure remote state for the commands that use the tfstate files. We do not configure it for
	// commands such as "get" or "version".
	switch cliContext.Args().First() {
	case "apply", "destroy", "import", "graph", "output", "plan", "push", "refresh", "show", "taint", "untaint", "validate":
		return remoteState.ConfigureRemoteState()
	case "remote":
		if cliContext.Args().Get(1) == "config" {
			// Encourage the user to configure remote state by defining it in .terragrunt and letting
			// Terragrunt handle it for them
			return errors.WithStackTrace(DontManuallyConfigureRemoteState)
		} else {
			// The other "terraform remote" commands explicitly push or pull state, so we shouldn't mess
			// with the configuration
			return nil
		}
	}

	return nil
}

// Run the given Terraform command with the given lock (if the command requires locking)
func runTerraformCommandWithLock(cliContext *cli.Context, lock locks.Lock) error {
	switch cliContext.Args().First() {
	case "apply", "destroy", "import":
		return locks.WithLock(lock, func() error { return runTerraformCommand(cliContext) })
	case "release-lock":
		return runReleaseLockCommand(cliContext, lock)
	default:
		return runTerraformCommand(cliContext)
	}
}

// Run the given Terraform command
func runTerraformCommand(cliContext *cli.Context) error {
	return shell.RunShellCommand("terraform", cliContext.Args()...)
}

// Release a lock, prompting the user for confirmation first
func runReleaseLockCommand(cliContext *cli.Context, lock locks.Lock) error {
	proceed, err := shell.PromptUserForYesNo(fmt.Sprintf("Are you sure you want to release %s?", lock))
	if err != nil {
		return err
	}

	if proceed {
		return lock.ReleaseLock()
	} else {
		return nil
	}
}

var DontManuallyConfigureRemoteState = fmt.Errorf("Instead of manually using the 'remote config' command, define your remote state settings in .terragrunt and Terragrunt will automatically configure it for you (and all your team members) next time you run it.")
<|endoftext|>


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

package main

import (
	"errors"
	"go/build"
	"testing"

	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
)

func TestInvalidEnsureFlagCombinations(t *testing.T) {
	ec := &ensureCommand{
		update: true,
		add:    true,
	}

	if err := ec.validateFlags(); err == nil {
		t.Error("-add and -update together should fail validation")
	}

	ec.vendorOnly, ec.add = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -update should fail validation")
	}

	ec.add, ec.update = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -add should fail validation")
	}

	ec.noVendor, ec.add = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -no-vendor should fail validation")
	}
	ec.noVendor = false

	// Also verify that the plain ensure path takes no args. This is a shady
	// test, as lots of other things COULD return errors, and we don't check
	// anything other than the error being non-nil. For now, it works well
	// because a panic will quickly result if the initial arg length validation
	// checks are incorrectly handled.
	if err := ec.runDefault(nil, []string{"foo"}, nil, nil, gps.SolveParameters{}); err == nil {
		t.Errorf("no args to plain ensure with -vendor-only")
	}
	ec.vendorOnly = false
	if err := ec.runDefault(nil, []string{"foo"}, nil, nil, gps.SolveParameters{}); err == nil {
		t.Errorf("no args to plain ensure")
	}
}

func TestCheckErrors(t *testing.T) {
	tt := []struct {
		name        string
		fatal       bool
		pkgOrErrMap map[string]pkgtree.PackageOrErr
	}{
		{
			name:  "noErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"mypkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "hasErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					Err: errors.New("code is busted"),
				},
			},
		},
		{
			name:  "onlyGoErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "onlyBuildErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "allGoErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
			},
		},
		{
			name:  "allMixedErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					Err: errors.New("code is busted"),
				},
			},
		},
	}

	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			fatal, err := checkErrors(tc.pkgOrErrMap)
			if tc.fatal != fatal {
				t.Fatalf("expected fatal flag to be %T, got %T", tc.fatal, fatal)
			}
			if err == nil && fatal {
				t.Fatal("unexpected fatal flag value while err is nil")
			}
		})
	}
}
<commit_msg>test(ensure): add TestValidateUpdateArgs<commit_after>// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"errors"
	"go/build"
	"io/ioutil"
	"log"
	"strings"
	"testing"

	"github.com/golang/dep"
	"github.com/golang/dep/internal/gps"
	"github.com/golang/dep/internal/gps/pkgtree"
	"github.com/golang/dep/internal/test"
)

func TestInvalidEnsureFlagCombinations(t *testing.T) {
	ec := &ensureCommand{
		update: true,
		add:    true,
	}

	if err := ec.validateFlags(); err == nil {
		t.Error("-add and -update together should fail validation")
	}

	ec.vendorOnly, ec.add = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -update should fail validation")
	}

	ec.add, ec.update = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -add should fail validation")
	}

	ec.noVendor, ec.add = true, false
	if err := ec.validateFlags(); err == nil {
		t.Error("-vendor-only with -no-vendor should fail validation")
	}
	ec.noVendor = false

	// Also verify that the plain ensure path takes no args. This is a shady
	// test, as lots of other things COULD return errors, and we don't check
	// anything other than the error being non-nil. For now, it works well
	// because a panic will quickly result if the initial arg length validation
	// checks are incorrectly handled.
	if err := ec.runDefault(nil, []string{"foo"}, nil, nil, gps.SolveParameters{}); err == nil {
		t.Errorf("no args to plain ensure with -vendor-only")
	}
	ec.vendorOnly = false
	if err := ec.runDefault(nil, []string{"foo"}, nil, nil, gps.SolveParameters{}); err == nil {
		t.Errorf("no args to plain ensure")
	}
}

func TestCheckErrors(t *testing.T) {
	tt := []struct {
		name        string
		fatal       bool
		pkgOrErrMap map[string]pkgtree.PackageOrErr
	}{
		{
			name:  "noErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"mypkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "hasErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					Err: errors.New("code is busted"),
				},
			},
		},
		{
			name:  "onlyGoErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "onlyBuildErrors",
			fatal: false,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					P: pkgtree.Package{},
				},
			},
		},
		{
			name:  "allGoErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
			},
		},
		{
			name:  "allMixedErrors",
			fatal: true,
			pkgOrErrMap: map[string]pkgtree.PackageOrErr{
				"github.com/me/pkg": {
					Err: &build.NoGoError{},
				},
				"github.com/someone/pkg": {
					Err: errors.New("code is busted"),
				},
			},
		},
	}

	for _, tc := range tt {
		t.Run(tc.name, func(t *testing.T) {
			fatal, err := checkErrors(tc.pkgOrErrMap)
			if tc.fatal != fatal {
				t.Fatalf("expected fatal flag to be %T, got %T", tc.fatal, fatal)
			}
			if err == nil && fatal {
				t.Fatal("unexpected fatal flag value while err is nil")
			}
		})
	}
}

func TestValidateUpdateArgs(t *testing.T) {
	cases := []struct {
		name           string
		args           []string
		wantError      error
		wantWarn       []string
		lockedProjects []string
	}{
		{
			name:      "empty args",
			args:      []string{},
			wantError: nil,
		},
		{
			name:      "not project root",
			args:      []string{"github.com/golang/dep/cmd"},
			wantError: errUpdateArgsValidation,
			wantWarn: []string{
				"github.com/golang/dep/cmd is not a project root, try github.com/golang/dep instead",
			},
		},
		{
			name:      "not present in lock",
			args:      []string{"github.com/golang/dep"},
			wantError: errUpdateArgsValidation,
			wantWarn: []string{
				"github.com/golang/dep is not present in Gopkg.lock, cannot -update it",
			},
		},
		{
			name:      "cannot specify alternate sources",
			args:      []string{"github.com/golang/dep:github.com/example/dep"},
			wantError: errUpdateArgsValidation,
			wantWarn: []string{
				"cannot specify alternate sources on -update (github.com/example/dep)",
			},
			lockedProjects: []string{"github.com/golang/dep"},
		},
		{
			name:      "version constraint passed",
			args:      []string{"github.com/golang/dep@master"},
			wantError: errUpdateArgsValidation,
			wantWarn: []string{
				"version constraint master passed for github.com/golang/dep, but -update follows constraints declared in Gopkg.toml, not CLI arguments",
			},
			lockedProjects: []string{"github.com/golang/dep"},
		},
	}

	h := test.NewHelper(t)
	defer h.Cleanup()

	h.TempDir("src")
	pwd := h.Path(".")

	stderrOutput := &bytes.Buffer{}
	errLogger := log.New(stderrOutput, "", 0)
	ctx := &dep.Ctx{
		GOPATH: pwd,
		Out:    log.New(ioutil.Discard, "", 0),
		Err:    errLogger,
	}

	sm, err := ctx.SourceManager()
	h.Must(err)
	defer sm.Release()

	p := new(dep.Project)
	params := p.MakeParams()

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			// Empty the buffer for every case
			stderrOutput.Reset()

			// Fill up the locked projects
			lockedProjects := []gps.LockedProject{}
			for _, lp := range c.lockedProjects {
				pi := gps.ProjectIdentifier{ProjectRoot: gps.ProjectRoot(lp)}
				lockedProjects = append(lockedProjects, gps.NewLockedProject(pi, gps.NewVersion("v1.0.0"), []string{}))
			}

			// Add lock to project
			p.Lock = &dep.Lock{P: lockedProjects}

			err := validateUpdateArgs(ctx, c.args, p, sm, &params)
			if err != c.wantError {
				t.Fatalf("Unexpected error while validating update args:\n\t(GOT): %v\n\t(WNT): %v", err, c.wantError)
			}

			warnings := stderrOutput.String()
			for _, warn := range c.wantWarn {
				if !strings.Contains(warnings, warn) {
					t.Fatalf("Expected validateUpdateArgs errors to contain: %q", warn)
				}
			}
		})
	}
}
<|endoftext|>


<commit_before>package command

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/go-metrics"
	"github.com/funkygao/gocli"
	"github.com/funkygao/golib/color"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
)

var (
	stats *peekStats
)

type peekStats struct {
	MsgCountPerSecond metrics.Meter
	MsgBytesPerSecond metrics.Meter
}

func newPeekStats() *peekStats {
	this := &peekStats{
		MsgCountPerSecond: metrics.NewMeter(),
		MsgBytesPerSecond: metrics.NewMeter(),
	}

	metrics.Register("msg.count.per.second", this.MsgCountPerSecond)
	metrics.Register("msg.bytes.per.second", this.MsgBytesPerSecond)
	return this
}

func (this *peekStats) start() {
	metrics.Log(metrics.DefaultRegistry, time.Second*10,
		log.New(os.Stdout, "metrics: ", log.Lmicroseconds))
}

type Peek struct {
	Ui  cli.Ui
	Cmd string

	offset   int64
	lastN    int64 // peek the most recent N messages
	colorize bool
	limit    int
	quit     chan struct{}
	once     sync.Once
}

func (this *Peek) Run(args []string) (exitCode int) {
	var (
		cluster      string
		zone         string
		topicPattern string
		partitionId  int
		silence      bool
	)
	cmdFlags := flag.NewFlagSet("peek", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	cmdFlags.StringVar(&zone, "z", ctx.ZkDefaultZone(), "")
	cmdFlags.StringVar(&cluster, "c", "", "")
	cmdFlags.StringVar(&topicPattern, "t", "", "")
	cmdFlags.IntVar(&partitionId, "p", 0, "")
	cmdFlags.BoolVar(&this.colorize, "color", true, "")
	cmdFlags.Int64Var(&this.lastN, "last", -1, "")
	cmdFlags.IntVar(&this.limit, "limit", -1, "")
	cmdFlags.Int64Var(&this.offset, "offset", sarama.OffsetNewest, "")
	cmdFlags.BoolVar(&silence, "s", false, "")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	this.quit = make(chan struct{})

	if silence {
		stats := newPeekStats()
		go stats.start()
	}

	zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
	msgChan := make(chan *sarama.ConsumerMessage, 20000) // msg aggerator channel
	if cluster == "" {
		zkzone.ForSortedClusters(func(zkcluster *zk.ZkCluster) {
			this.consumeCluster(zkcluster, topicPattern, partitionId, msgChan)
		})
	} else {
		zkcluster := zkzone.NewCluster(cluster)
		this.consumeCluster(zkcluster, topicPattern, partitionId, msgChan)
	}

	signal.RegisterSignalsHandler(func(sig os.Signal) {
		log.Printf("received signal: %s", strings.ToUpper(sig.String()))
		log.Println("quiting...")

		this.once.Do(func() {
			close(this.quit)
		})
	}, syscall.SIGINT, syscall.SIGTERM)

	var (
		startAt = time.Now()
		msg     *sarama.ConsumerMessage
		total   int
		bytes   int64
	)

LOOP:
	for {
		select {
		case <-this.quit:
			this.Ui.Output(fmt.Sprintf("Total: %s msgs, %s, elapsed: %s",
				gofmt.Comma(int64(total)), gofmt.ByteSize(bytes), time.Since(startAt)))
			elapsed := time.Since(startAt).Seconds()
			if elapsed > 0. {
				this.Ui.Output(fmt.Sprintf("Speed: %d/s", total/int(elapsed)))
			}

			return

		case msg = <-msgChan:
			if silence {
				stats.MsgCountPerSecond.Mark(1)
				stats.MsgBytesPerSecond.Mark(int64(len(msg.Value)))
			} else {
				if this.colorize {
					this.Ui.Output(fmt.Sprintf("%s/%d %s k:%s, v:%s",
						color.Green(msg.Topic), msg.Partition,
						gofmt.Comma(msg.Offset), string(msg.Key), string(msg.Value)))
				} else {
					// colored UI will have invisible chars output
					fmt.Println(fmt.Sprintf("%s/%d %s k:%s, v:%s",
						msg.Topic, msg.Partition,
						gofmt.Comma(msg.Offset), string(msg.Key), string(msg.Value)))
				}
			}

			total++
			bytes += int64(len(msg.Value))

			if this.limit > 0 && total >= this.limit {
				break LOOP

			}
			if this.lastN > 0 && total >= int(this.lastN) {
				break LOOP
			}

		}
	}

	return
}

func (this *Peek) consumeCluster(zkcluster *zk.ZkCluster, topicPattern string,
	partitionId int, msgChan chan *sarama.ConsumerMessage) {
	brokerList := zkcluster.BrokerList()
	if len(brokerList) == 0 {
		return
	}
	kfk, err := sarama.NewClient(brokerList, sarama.NewConfig())
	if err != nil {
		this.Ui.Output(err.Error())
		return
	}
	//defer kfk.Close() // FIXME how to close it

	topics, err := kfk.Topics()
	if err != nil {
		this.Ui.Output(err.Error())
		return
	}

	for _, t := range topics {
		if patternMatched(t, topicPattern) {
			go this.simpleConsumeTopic(kfk, t, int32(partitionId), msgChan)
		}
	}

}

func (this *Peek) simpleConsumeTopic(kfk sarama.Client, topic string, partitionId int32,
	msgCh chan *sarama.ConsumerMessage) {
	consumer, err := sarama.NewConsumerFromClient(kfk)
	if err != nil {
		panic(err)
	}
	defer consumer.Close()

	if partitionId == -1 {
		// all partitions
		partitions, err := kfk.Partitions(topic)
		if err != nil {
			panic(err)
		}

		for _, p := range partitions {
			offset := this.offset
			if this.lastN > 0 {
				latestOffset, err := kfk.GetOffset(topic, p, sarama.OffsetNewest)
				swallow(err)

				oldestOffset, err := kfk.GetOffset(topic, p, sarama.OffsetOldest)
				swallow(err)

				offset = latestOffset - this.lastN
				if offset < oldestOffset {
					offset = oldestOffset
				}

				if offset == 0 {
					// no message in store
					return
				}
			}

			go this.consumePartition(kfk, consumer, topic, p, msgCh, offset)
		}

	} else {
		offset := this.offset
		if this.lastN > 0 {
			latestOffset, err := kfk.GetOffset(topic, partitionId, sarama.OffsetNewest)
			swallow(err)
			offset = latestOffset - this.lastN
			if offset < 0 {
				offset = sarama.OffsetOldest
			}
		}
		this.consumePartition(kfk, consumer, topic, partitionId, msgCh, offset)
	}

}

func (this *Peek) consumePartition(kfk sarama.Client, consumer sarama.Consumer,
	topic string, partitionId int32, msgCh chan *sarama.ConsumerMessage, offset int64) {
	p, err := consumer.ConsumePartition(topic, partitionId, offset)
	if err != nil {
		this.Ui.Error(fmt.Sprintf("%s/%d: offset=%d %v", topic, partitionId, offset, err))
		return
	}
	defer p.Close()

	n := int64(0)
	for {
		select {
		case <-this.quit:
			return

		case msg := <-p.Messages():
			msgCh <- msg

			n++
			if this.lastN > 0 && n >= this.lastN {
				return
			}
		}
	}
}

func (*Peek) Synopsis() string {
	return "Peek kafka cluster messages ongoing from any offset"
}

func (this *Peek) Help() string {
	help := fmt.Sprintf(`
Usage: %s peek [options]

    Peek kafka cluster messages ongoing from any offset

Options:

    -z zone
      Default %s

    -c cluster

    -t topic pattern

    -p partition id
      -1 will peek all partitions of a topic

    -last n
      Peek the most recent N messages

    -offset message offset value
      -1 OffsetNewest, -2 OffsetOldest.
      You can specify your own offset.
      Default -1(OffsetNewest)

    -limit n
      Limit how many messages to consume

    -s
      Silence mode, only display statastics instead of message content

    -color
      Enable colorized output
`, this.Cmd, ctx.ZkDefaultZone())
	return strings.TrimSpace(help)
}
<commit_msg>fix divide by zero problem<commit_after>package command

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/go-metrics"
	"github.com/funkygao/gocli"
	"github.com/funkygao/golib/color"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
)

var (
	stats *peekStats
)

type peekStats struct {
	MsgCountPerSecond metrics.Meter
	MsgBytesPerSecond metrics.Meter
}

func newPeekStats() *peekStats {
	this := &peekStats{
		MsgCountPerSecond: metrics.NewMeter(),
		MsgBytesPerSecond: metrics.NewMeter(),
	}

	metrics.Register("msg.count.per.second", this.MsgCountPerSecond)
	metrics.Register("msg.bytes.per.second", this.MsgBytesPerSecond)
	return this
}

func (this *peekStats) start() {
	metrics.Log(metrics.DefaultRegistry, time.Second*10,
		log.New(os.Stdout, "metrics: ", log.Lmicroseconds))
}

type Peek struct {
	Ui  cli.Ui
	Cmd string

	offset   int64
	lastN    int64 // peek the most recent N messages
	colorize bool
	limit    int
	quit     chan struct{}
	once     sync.Once
}

func (this *Peek) Run(args []string) (exitCode int) {
	var (
		cluster      string
		zone         string
		topicPattern string
		partitionId  int
		silence      bool
	)
	cmdFlags := flag.NewFlagSet("peek", flag.ContinueOnError)
	cmdFlags.Usage = func() { this.Ui.Output(this.Help()) }
	cmdFlags.StringVar(&zone, "z", ctx.ZkDefaultZone(), "")
	cmdFlags.StringVar(&cluster, "c", "", "")
	cmdFlags.StringVar(&topicPattern, "t", "", "")
	cmdFlags.IntVar(&partitionId, "p", 0, "")
	cmdFlags.BoolVar(&this.colorize, "color", true, "")
	cmdFlags.Int64Var(&this.lastN, "last", -1, "")
	cmdFlags.IntVar(&this.limit, "limit", -1, "")
	cmdFlags.Int64Var(&this.offset, "offset", sarama.OffsetNewest, "")
	cmdFlags.BoolVar(&silence, "s", false, "")
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	this.quit = make(chan struct{})

	if silence {
		stats := newPeekStats()
		go stats.start()
	}

	zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
	msgChan := make(chan *sarama.ConsumerMessage, 20000) // msg aggerator channel
	if cluster == "" {
		zkzone.ForSortedClusters(func(zkcluster *zk.ZkCluster) {
			this.consumeCluster(zkcluster, topicPattern, partitionId, msgChan)
		})
	} else {
		zkcluster := zkzone.NewCluster(cluster)
		this.consumeCluster(zkcluster, topicPattern, partitionId, msgChan)
	}

	signal.RegisterSignalsHandler(func(sig os.Signal) {
		log.Printf("received signal: %s", strings.ToUpper(sig.String()))
		log.Println("quiting...")

		this.once.Do(func() {
			close(this.quit)
		})
	}, syscall.SIGINT, syscall.SIGTERM)

	var (
		startAt = time.Now()
		msg     *sarama.ConsumerMessage
		total   int
		bytes   int64
	)

LOOP:
	for {
		select {
		case <-this.quit:
			this.Ui.Output(fmt.Sprintf("Total: %s msgs, %s, elapsed: %s",
				gofmt.Comma(int64(total)), gofmt.ByteSize(bytes), time.Since(startAt)))
			elapsed := time.Since(startAt).Seconds()
			if elapsed > 1. {
				this.Ui.Output(fmt.Sprintf("Speed: %d/s", total/int(elapsed)))
			}

			return

		case msg = <-msgChan:
			if silence {
				stats.MsgCountPerSecond.Mark(1)
				stats.MsgBytesPerSecond.Mark(int64(len(msg.Value)))
			} else {
				if this.colorize {
					this.Ui.Output(fmt.Sprintf("%s/%d %s k:%s, v:%s",
						color.Green(msg.Topic), msg.Partition,
						gofmt.Comma(msg.Offset), string(msg.Key), string(msg.Value)))
				} else {
					// colored UI will have invisible chars output
					fmt.Println(fmt.Sprintf("%s/%d %s k:%s, v:%s",
						msg.Topic, msg.Partition,
						gofmt.Comma(msg.Offset), string(msg.Key), string(msg.Value)))
				}
			}

			total++
			bytes += int64(len(msg.Value))

			if this.limit > 0 && total >= this.limit {
				break LOOP

			}
			if this.lastN > 0 && total >= int(this.lastN) {
				break LOOP
			}

		}
	}

	return
}

func (this *Peek) consumeCluster(zkcluster *zk.ZkCluster, topicPattern string,
	partitionId int, msgChan chan *sarama.ConsumerMessage) {
	brokerList := zkcluster.BrokerList()
	if len(brokerList) == 0 {
		return
	}
	kfk, err := sarama.NewClient(brokerList, sarama.NewConfig())
	if err != nil {
		this.Ui.Output(err.Error())
		return
	}
	//defer kfk.Close() // FIXME how to close it

	topics, err := kfk.Topics()
	if err != nil {
		this.Ui.Output(err.Error())
		return
	}

	for _, t := range topics {
		if patternMatched(t, topicPattern) {
			go this.simpleConsumeTopic(kfk, t, int32(partitionId), msgChan)
		}
	}

}

func (this *Peek) simpleConsumeTopic(kfk sarama.Client, topic string, partitionId int32,
	msgCh chan *sarama.ConsumerMessage) {
	consumer, err := sarama.NewConsumerFromClient(kfk)
	if err != nil {
		panic(err)
	}
	defer consumer.Close()

	if partitionId == -1 {
		// all partitions
		partitions, err := kfk.Partitions(topic)
		if err != nil {
			panic(err)
		}

		for _, p := range partitions {
			offset := this.offset
			if this.lastN > 0 {
				latestOffset, err := kfk.GetOffset(topic, p, sarama.OffsetNewest)
				swallow(err)

				oldestOffset, err := kfk.GetOffset(topic, p, sarama.OffsetOldest)
				swallow(err)

				offset = latestOffset - this.lastN
				if offset < oldestOffset {
					offset = oldestOffset
				}

				if offset == 0 {
					// no message in store
					return
				}
			}

			go this.consumePartition(kfk, consumer, topic, p, msgCh, offset)
		}

	} else {
		offset := this.offset
		if this.lastN > 0 {
			latestOffset, err := kfk.GetOffset(topic, partitionId, sarama.OffsetNewest)
			swallow(err)
			offset = latestOffset - this.lastN
			if offset < 0 {
				offset = sarama.OffsetOldest
			}
		}
		this.consumePartition(kfk, consumer, topic, partitionId, msgCh, offset)
	}

}

func (this *Peek) consumePartition(kfk sarama.Client, consumer sarama.Consumer,
	topic string, partitionId int32, msgCh chan *sarama.ConsumerMessage, offset int64) {
	p, err := consumer.ConsumePartition(topic, partitionId, offset)
	if err != nil {
		this.Ui.Error(fmt.Sprintf("%s/%d: offset=%d %v", topic, partitionId, offset, err))
		return
	}
	defer p.Close()

	n := int64(0)
	for {
		select {
		case <-this.quit:
			return

		case msg := <-p.Messages():
			msgCh <- msg

			n++
			if this.lastN > 0 && n >= this.lastN {
				return
			}
		}
	}
}

func (*Peek) Synopsis() string {
	return "Peek kafka cluster messages ongoing from any offset"
}

func (this *Peek) Help() string {
	help := fmt.Sprintf(`
Usage: %s peek [options]

    Peek kafka cluster messages ongoing from any offset

Options:

    -z zone
      Default %s

    -c cluster

    -t topic pattern

    -p partition id
      -1 will peek all partitions of a topic

    -last n
      Peek the most recent N messages

    -offset message offset value
      -1 OffsetNewest, -2 OffsetOldest.
      You can specify your own offset.
      Default -1(OffsetNewest)

    -limit n
      Limit how many messages to consume

    -s
      Silence mode, only display statastics instead of message content

    -color
      Enable colorized output
`, this.Cmd, ctx.ZkDefaultZone())
	return strings.TrimSpace(help)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gobs/args"
	"github.com/gobs/cmd"
	"github.com/gobs/cmd/plugins/controlflow"
	"github.com/gobs/cmd/plugins/json"
	"github.com/gobs/cmd/plugins/stats"
	"github.com/gobs/httpclient"
	"github.com/gobs/simplejson"

	"golang.org/x/net/publicsuffix"
	"net/http/cookiejar"

	"encoding/base64"
	"fmt"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	reFieldValue = regexp.MustCompile(`(\w[\d\w-]*)(=(.*))?`) // field-name=value
)

func request(cmd *cmd.Cmd, client *httpclient.HttpClient, method, params string, print, trace bool) *httpclient.HttpResponse {
	cmd.SetVar("error", "")
	cmd.SetVar("body", "")

	// [-options...] "path" {body}

	options := []httpclient.RequestOption{httpclient.Method(method)}

	var rtrace *httpclient.RequestTrace

	if trace {
		rtrace = &httpclient.RequestTrace{}
		options = append(options, httpclient.Trace(rtrace.NewClientTrace(true)))
	}

	args := args.ParseArgs(params, args.InfieldBrackets())

	if len(args.Arguments) > 0 {
		options = append(options, client.Path(args.Arguments[0]))
	}

	if len(args.Arguments) > 1 {
		data := strings.Join(args.Arguments[1:], " ")
		options = append(options, httpclient.Body(strings.NewReader(data)))
	}

	if len(args.Options) > 0 {
		options = append(options, httpclient.StringParams(args.Options))
	}

	res, err := client.SendRequest(options...)
	if rtrace != nil {
		rtrace.Done()
	}
	if err == nil {
		err = res.ResponseError()
	}
	if err != nil {
		fmt.Println("ERROR:", err)
		cmd.SetVar("error", err)
	}

	body := res.Content()
	if len(body) > 0 && print {
		if strings.Contains(res.Header.Get("Content-Type"), "json") {
			jbody, err := simplejson.LoadBytes(body)
			if err != nil {
				fmt.Println(err)
			} else {
				json.PrintJson(jbody.Data())
			}
		} else {
			fmt.Println(string(body))
		}
	}

	//cookies := res.Cookies()
	//if len(cookies) > 0 {
	//        client.Cookies = cookies
	//}

	cmd.SetVar("body", string(body))
	if rtrace != nil {
		cmd.SetVar("rtrace", simplejson.MustDumpString(rtrace))
	}

	return res
}

func headerName(s string) string {
	s = strings.ToLower(s)
	parts := strings.Split(s, "-")
	for i, p := range parts {
		if len(p) > 0 {
			parts[i] = strings.ToUpper(p[0:1]) + p[1:]
		}
	}
	return strings.Join(parts, "-")
}

func unquote(s string) string {
	if res, err := strconv.Unquote(strings.TrimSpace(s)); err == nil {
		return res
	}

	return s
}

func parseValue(v string) (interface{}, error) {
	switch {
	case strings.HasPrefix(v, "{") || strings.HasPrefix(v, "["):
		j, err := simplejson.LoadString(v)
		if err != nil {
			return nil, fmt.Errorf("error parsing %q", v)
		} else {
			return j.Data(), nil
		}

	case strings.HasPrefix(v, `"`):
		return strings.Trim(v, `"`), nil

	case strings.HasPrefix(v, `'`):
		return strings.Trim(v, `'`), nil

	case v == "":
		return v, nil

	case v == "true":
		return true, nil

	case v == "false":
		return false, nil

	case v == "null":
		return nil, nil

	default:
		if i, err := strconv.ParseInt(v, 10, 64); err == nil {
			return i, nil
		}
		if f, err := strconv.ParseFloat(v, 64); err == nil {
			return f, nil
		}

		return v, nil
	}
}

func main() {
	var interrupted bool
	var logBody bool
	var client = httpclient.NewHttpClient("")

	client.UserAgent = "httpclient/0.1"

	commander := &cmd.Cmd{
		HistoryFile: ".httpclient_history",
		EnableShell: true,
		Interrupt:   func(sig os.Signal) bool { interrupted = true; return false },
	}

	commander.Init(controlflow.Plugin, json.Plugin, stats.Plugin)

	commander.Add(cmd.Command{
		"base",
		`base [url]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.BaseURL = val
				commander.SetPrompt(fmt.Sprintf("%v> ", client.BaseURL), 40)
				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Println("base", client.BaseURL)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"insecure",
		`insecure [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.AllowInsecure(val)
			}

			// assume if there is a transport, it's because we set AllowInsecure
			fmt.Println("insecure", client.GetTransport() != nil)

			return
		},
		nil})

	commander.Add(cmd.Command{
		"timeout",
		`timeout [duration]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := time.ParseDuration(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.SetTimeout(val)
			}

			fmt.Println("timeout", client.GetTimeout())
			return
		},
		nil})

	commander.Add(cmd.Command{
		"verbose",
		`verbose [true|false|body]`,
		func(line string) (stop bool) {
			if line == "body" {
				if !logBody {
					httpclient.StartLogging(true, true, true)
					logBody = true
				}
			} else if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.Verbose = val

				if !val && logBody {
					httpclient.StopLogging()
					logBody = false
				}
			}

			fmt.Println("Verbose", client.Verbose)
			if logBody {
				fmt.Println("Logging Request/Response body")
			}
			return
		},
		nil})

	commander.Add(cmd.Command{
		"timing",
		`timing [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				commander.Timing = val
			}

			fmt.Println("Timing", commander.Timing)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"agent",
		`agent user-agent-string`,
		func(line string) (stop bool) {
			if line != "" {
				client.UserAgent = line
			}

			fmt.Println("User-Agent:", client.UserAgent)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"header",
		`header [name [value]]`,
		func(line string) (stop bool) {
			if line == "" {
				if len(client.Headers) == 0 {
					fmt.Println("No headers")
				} else {
					fmt.Println("Headers:")
					for k, v := range client.Headers {
						fmt.Printf("  %v: %v\n", k, v)
					}
				}

				return
			}

			parts := args.GetArgsN(line, 2)
			name := headerName(parts[0])

			if len(parts) == 2 {
				value := unquote(parts[1])

				if value == "" {
					delete(client.Headers, name)
				} else {
					client.Headers[name] = value
				}

				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Printf("%v: %v\n", name, client.Headers[name])
			return
		},
		nil})

	commander.Add(cmd.Command{"head",
		`
                head [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			res := request(commander, client, "head", line, false, commander.GetBoolVar("trace"))
			if res != nil {
				json.PrintJson(res.Header)
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"get",
		`
                get [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "get", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"post",
		`
                post [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "post", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"put",
		`
                put [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "put", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"delete",
		`
                delete [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "delete", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"jwt",
		`
                jwt token
                `,
		func(line string) (stop bool) {
			parts := strings.Split(line, ".")
			if len(parts) != 3 {
				fmt.Println("not a JWT token")
			}

			decoded, err := base64.RawStdEncoding.DecodeString(parts[1])
			if err != nil {
				fmt.Println(err)
			} else {
				fmt.Println(string(decoded))
				commander.SetVar("body", string(decoded))
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"cookiejar",
		`
                cookiejar [--add|--delete|domain]
                `,
		func(line string) (stop bool) {
			if line == "--add" {
				if client.GetCookieJar() != nil {
					fmt.Println("you already have a cookie jar")
					return
				}

				jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
				if err != nil {
					fmt.Println("cannot create cookiejar:", err)
					commander.SetVar("error", err)
				}

				client.SetCookieJar(jar)
				fmt.Println("cookiejar added")
			} else if line == "--delete" || line == "--remove" {
				client.SetCookieJar(nil)
				fmt.Println("cookiejar removed")
			} else if strings.HasPrefix(line, "-") {
				fmt.Println("invalid option", line)
				fmt.Println("usage: cookiejar [--add|--delete]")
			} else if line != "" {
				if client.GetCookieJar() == nil {
					fmt.Println("no cookiejar")
					return
				}

				u, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					commander.SetVar("error", err)
					return
				}

				cookies := client.GetCookieJar().Cookies(u)
				if len(cookies) == 0 {
					fmt.Println("no cookies in the cookiejar")
					return
				}

				for _, cookie := range cookies {
					fmt.Printf("  %s: %s\n", cookie.Name, cookie.Value)
				}
			}

			return
		},
		nil})

	commander.Commands["set"] = commander.Commands["var"]

	switch len(os.Args) {
	case 1: // program name only
		break

	case 2: // one arg - expect URL or @filename
		cmd := os.Args[1]
		if !strings.HasPrefix(cmd, "@") {
			cmd = "base " + cmd
		}

		if commander.OneCmd(cmd) {
			return
		}

	case 3:
		if os.Args[1] == "-script" || os.Args[1] == "--script" {
			cmd := "@" + os.Args[2]
			commander.OneCmd(cmd)
		} else {
			fmt.Println("usage:", os.Args[0], "[{base-url} | @{script-file} | -script {script-file}]")
		}

		return

	default:
		fmt.Println("usage:", os.Args[0], "[{base-url} | @{script-file} | -script {script-file}]")
		return
	}

	commander.CmdLoop()
}
<commit_msg>Added "serve" command to quickly start a local server<commit_after>package main

import (
	"github.com/gobs/args"
	"github.com/gobs/cmd"
	"github.com/gobs/cmd/plugins/controlflow"
	"github.com/gobs/cmd/plugins/json"
	"github.com/gobs/cmd/plugins/stats"
	"github.com/gobs/httpclient"
	"github.com/gobs/simplejson"

	"golang.org/x/net/publicsuffix"
	"net/http"
	"net/http/cookiejar"

	"encoding/base64"
	"fmt"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var (
	reFieldValue = regexp.MustCompile(`(\w[\d\w-]*)(=(.*))?`) // field-name=value
)

func request(cmd *cmd.Cmd, client *httpclient.HttpClient, method, params string, print, trace bool) *httpclient.HttpResponse {
	cmd.SetVar("error", "")
	cmd.SetVar("body", "")

	// [-options...] "path" {body}

	options := []httpclient.RequestOption{httpclient.Method(method)}

	var rtrace *httpclient.RequestTrace

	if trace {
		rtrace = &httpclient.RequestTrace{}
		options = append(options, httpclient.Trace(rtrace.NewClientTrace(true)))
	}

	args := args.ParseArgs(params, args.InfieldBrackets())

	if len(args.Arguments) > 0 {
		options = append(options, client.Path(args.Arguments[0]))
	}

	if len(args.Arguments) > 1 {
		data := strings.Join(args.Arguments[1:], " ")
		options = append(options, httpclient.Body(strings.NewReader(data)))
	}

	if len(args.Options) > 0 {
		options = append(options, httpclient.StringParams(args.Options))
	}

	res, err := client.SendRequest(options...)
	if rtrace != nil {
		rtrace.Done()
	}
	if err == nil {
		err = res.ResponseError()
	}
	if err != nil {
		fmt.Println("ERROR:", err)
		cmd.SetVar("error", err)
	}

	body := res.Content()
	if len(body) > 0 && print {
		if strings.Contains(res.Header.Get("Content-Type"), "json") {
			jbody, err := simplejson.LoadBytes(body)
			if err != nil {
				fmt.Println(err)
			} else {
				json.PrintJson(jbody.Data())
			}
		} else {
			fmt.Println(string(body))
		}
	}

	//cookies := res.Cookies()
	//if len(cookies) > 0 {
	//        client.Cookies = cookies
	//}

	cmd.SetVar("body", string(body))
	if rtrace != nil {
		cmd.SetVar("rtrace", simplejson.MustDumpString(rtrace))
	}

	return res
}

func headerName(s string) string {
	s = strings.ToLower(s)
	parts := strings.Split(s, "-")
	for i, p := range parts {
		if len(p) > 0 {
			parts[i] = strings.ToUpper(p[0:1]) + p[1:]
		}
	}
	return strings.Join(parts, "-")
}

func unquote(s string) string {
	if res, err := strconv.Unquote(strings.TrimSpace(s)); err == nil {
		return res
	}

	return s
}

func parseValue(v string) (interface{}, error) {
	switch {
	case strings.HasPrefix(v, "{") || strings.HasPrefix(v, "["):
		j, err := simplejson.LoadString(v)
		if err != nil {
			return nil, fmt.Errorf("error parsing %q", v)
		} else {
			return j.Data(), nil
		}

	case strings.HasPrefix(v, `"`):
		return strings.Trim(v, `"`), nil

	case strings.HasPrefix(v, `'`):
		return strings.Trim(v, `'`), nil

	case v == "":
		return v, nil

	case v == "true":
		return true, nil

	case v == "false":
		return false, nil

	case v == "null":
		return nil, nil

	default:
		if i, err := strconv.ParseInt(v, 10, 64); err == nil {
			return i, nil
		}
		if f, err := strconv.ParseFloat(v, 64); err == nil {
			return f, nil
		}

		return v, nil
	}
}

func main() {
	var interrupted bool
	var logBody bool
	var client = httpclient.NewHttpClient("")

	client.UserAgent = "httpclient/0.1"

	commander := &cmd.Cmd{
		HistoryFile: ".httpclient_history",
		EnableShell: true,
		Interrupt:   func(sig os.Signal) bool { interrupted = true; return false },
	}

	commander.Init(controlflow.Plugin, json.Plugin, stats.Plugin)

	commander.Add(cmd.Command{
		"base",
		`base [url]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.BaseURL = val
				commander.SetPrompt(fmt.Sprintf("%v> ", client.BaseURL), 40)
				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Println("base", client.BaseURL)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"insecure",
		`insecure [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.AllowInsecure(val)
			}

			// assume if there is a transport, it's because we set AllowInsecure
			fmt.Println("insecure", client.GetTransport() != nil)

			return
		},
		nil})

	commander.Add(cmd.Command{
		"timeout",
		`timeout [duration]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := time.ParseDuration(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.SetTimeout(val)
			}

			fmt.Println("timeout", client.GetTimeout())
			return
		},
		nil})

	commander.Add(cmd.Command{
		"verbose",
		`verbose [true|false|body]`,
		func(line string) (stop bool) {
			if line == "body" {
				if !logBody {
					httpclient.StartLogging(true, true, true)
					logBody = true
				}
			} else if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				client.Verbose = val

				if !val && logBody {
					httpclient.StopLogging()
					logBody = false
				}
			}

			fmt.Println("Verbose", client.Verbose)
			if logBody {
				fmt.Println("Logging Request/Response body")
			}
			return
		},
		nil})

	commander.Add(cmd.Command{
		"timing",
		`timing [true|false]`,
		func(line string) (stop bool) {
			if line != "" {
				val, err := strconv.ParseBool(line)
				if err != nil {
					fmt.Println(err)
					return
				}

				commander.Timing = val
			}

			fmt.Println("Timing", commander.Timing)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"agent",
		`agent user-agent-string`,
		func(line string) (stop bool) {
			if line != "" {
				client.UserAgent = line
			}

			fmt.Println("User-Agent:", client.UserAgent)
			return
		},
		nil})

	commander.Add(cmd.Command{
		"header",
		`header [name [value]]`,
		func(line string) (stop bool) {
			if line == "" {
				if len(client.Headers) == 0 {
					fmt.Println("No headers")
				} else {
					fmt.Println("Headers:")
					for k, v := range client.Headers {
						fmt.Printf("  %v: %v\n", k, v)
					}
				}

				return
			}

			parts := args.GetArgsN(line, 2)
			name := headerName(parts[0])

			if len(parts) == 2 {
				value := unquote(parts[1])

				if value == "" {
					delete(client.Headers, name)
				} else {
					client.Headers[name] = value
				}

				if !commander.GetBoolVar("print") {
					return
				}
			}

			fmt.Printf("%v: %v\n", name, client.Headers[name])
			return
		},
		nil})

	commander.Add(cmd.Command{"head",
		`
                head [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			res := request(commander, client, "head", line, false, commander.GetBoolVar("trace"))
			if res != nil {
				json.PrintJson(res.Header)
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"get",
		`
                get [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "get", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"post",
		`
                post [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "post", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"put",
		`
                put [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "put", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"delete",
		`
                delete [url-path] [short-data]
                `,
		func(line string) (stop bool) {
			request(commander, client, "delete", line, commander.GetBoolVar("print"), commander.GetBoolVar("trace"))
			return
		},
		nil})

	commander.Add(cmd.Command{"jwt",
		`
                jwt token
                `,
		func(line string) (stop bool) {
			parts := strings.Split(line, ".")
			if len(parts) != 3 {
				fmt.Println("not a JWT token")
			}

			decoded, err := base64.RawStdEncoding.DecodeString(parts[1])
			if err != nil {
				fmt.Println(err)
			} else {
				fmt.Println(string(decoded))
				commander.SetVar("body", string(decoded))
			}
			return
		},
		nil})

	commander.Add(cmd.Command{"cookiejar",
		`
                cookiejar [--add|--delete|domain]
                `,
		func(line string) (stop bool) {
			if line == "--add" {
				if client.GetCookieJar() != nil {
					fmt.Println("you already have a cookie jar")
					return
				}

				jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
				if err != nil {
					fmt.Println("cannot create cookiejar:", err)
					commander.SetVar("error", err)
				}

				client.SetCookieJar(jar)
				fmt.Println("cookiejar added")
			} else if line == "--delete" || line == "--remove" {
				client.SetCookieJar(nil)
				fmt.Println("cookiejar removed")
			} else if strings.HasPrefix(line, "-") {
				fmt.Println("invalid option", line)
				fmt.Println("usage: cookiejar [--add|--delete]")
			} else if line != "" {
				if client.GetCookieJar() == nil {
					fmt.Println("no cookiejar")
					return
				}

				u, err := url.Parse(line)
				if err != nil {
					fmt.Println(err)
					commander.SetVar("error", err)
					return
				}

				cookies := client.GetCookieJar().Cookies(u)
				if len(cookies) == 0 {
					fmt.Println("no cookies in the cookiejar")
					return
				}

				for _, cookie := range cookies {
					fmt.Printf("  %s: %s\n", cookie.Name, cookie.Value)
				}
			}

			return
		},
		nil})

	commander.Add(cmd.Command{"serve",
		`
                serve [[host]:port] [dir]
                `,
		func(line string) (stop bool) {
			port := ":3000"
			dir := "."

			parts := strings.Fields(line)
			if len(parts) > 2 {
				fmt.Println("too many arguments")
				fmt.Println()
				fmt.Println("usage: serve [[host]:port] [dir]")
				return
			}

			for _, p := range parts {
				if strings.Contains(p, ":") {
					port = p
				} else {
					dir = p
				}
			}

			fmt.Printf("Serving directory %q on port %v\n", dir, port)
			if err := http.ListenAndServe(port, http.FileServer(http.Dir(dir))); err != nil {
				fmt.Println(err)
			}

			return
		},
		nil})

	commander.Commands["set"] = commander.Commands["var"]

	if len(os.Args) > 1 && os.Args[1] == "serve" {
		commander.OneCmd(strings.Join(os.Args[1:], " "))
		return
	}

	switch len(os.Args) {
	case 1: // program name only
		break

	case 2: // one arg - expect URL or @filename
		cmd := os.Args[1]
		if !strings.HasPrefix(cmd, "@") {
			cmd = "base " + cmd
		}

		if commander.OneCmd(cmd) {
			return
		}

	case 3:
		if os.Args[1] == "-script" || os.Args[1] == "--script" {
			cmd := "@" + os.Args[2]
			commander.OneCmd(cmd)
		} else {
			fmt.Println("usage:", os.Args[0], "[{base-url} | @{script-file} | -script {script-file}]")
		}

		return

	default:
		fmt.Println("usage:", os.Args[0], "[{base-url} | @{script-file} | -script {script-file}]")
		return
	}

	commander.CmdLoop()
}
<|endoftext|>


<commit_before>package main

import (
	"net"
	_ "net/http/pprof"
	"strconv"

	"github.com/go-kit/kit/log"
	"github.com/piotrkowalczuk/mnemosyne/mnemosyned"
	"github.com/piotrkowalczuk/sklog"
	"google.golang.org/grpc/grpclog"
)

var config configuration

func init() {
	config.init()
}

func main() {
	config.parse()

	logger := initLogger(config.logger.adapter, config.logger.format, config.logger.level, sklog.KeySubsystem, config.subsystem)
	rpcListener := initListener(logger, config.host, config.port)
	debugListener := initListener(logger, config.host, config.port+1)

	daemon, err := mnemosyned.NewDaemon(&mnemosyned.DaemonOpts{
		Namespace:              config.namespace,
		Subsystem:              config.subsystem,
		SessionTTL:             config.session.ttl,
		SessionTTC:             config.session.ttc,
		TLS:                    config.tls.enabled,
		TLSCertFile:            config.tls.certFile,
		TLSKeyFile:             config.tls.keyFile,
		MonitoringEngine:       config.monitoring.engine,
		StorageEngine:          config.storage.engine,
		StoragePostgresAddress: config.storage.postgres.address,
		StoragePostgresTable:   config.storage.postgres.table,
		Logger:                 logger,
		RPCListener:            rpcListener,
		DebugListener:          debugListener,
	})
	if err != nil {
		sklog.Fatal(logger, err)
	}

	grpclog.SetLogger(sklog.NewGRPCLogger(logger))
	if err := daemon.Run(); err != nil {
		sklog.Fatal(logger, err)
	}
	defer daemon.Close()

	done := make(chan struct{})
	<-done
}

func initListener(logger log.Logger, host string, port int) net.Listener {
	on := host + ":" + strconv.FormatInt(int64(port), 10)
	listener, err := net.Listen("tcp", on)
	if err != nil {
		sklog.Fatal(logger, err)
	}
	return listener
}
<commit_msg>redundant pprof import removed<commit_after>package main

import (
	"net"
	"strconv"

	"github.com/go-kit/kit/log"
	"github.com/piotrkowalczuk/mnemosyne/mnemosyned"
	"github.com/piotrkowalczuk/sklog"
	"google.golang.org/grpc/grpclog"
)

var config configuration

func init() {
	config.init()
}

func main() {
	config.parse()

	logger := initLogger(config.logger.adapter, config.logger.format, config.logger.level, sklog.KeySubsystem, config.subsystem)
	rpcListener := initListener(logger, config.host, config.port)
	debugListener := initListener(logger, config.host, config.port+1)

	daemon, err := mnemosyned.NewDaemon(&mnemosyned.DaemonOpts{
		Namespace:              config.namespace,
		Subsystem:              config.subsystem,
		SessionTTL:             config.session.ttl,
		SessionTTC:             config.session.ttc,
		TLS:                    config.tls.enabled,
		TLSCertFile:            config.tls.certFile,
		TLSKeyFile:             config.tls.keyFile,
		MonitoringEngine:       config.monitoring.engine,
		StorageEngine:          config.storage.engine,
		StoragePostgresAddress: config.storage.postgres.address,
		StoragePostgresTable:   config.storage.postgres.table,
		Logger:                 logger,
		RPCListener:            rpcListener,
		DebugListener:          debugListener,
	})
	if err != nil {
		sklog.Fatal(logger, err)
	}

	grpclog.SetLogger(sklog.NewGRPCLogger(logger))
	if err := daemon.Run(); err != nil {
		sklog.Fatal(logger, err)
	}
	defer daemon.Close()

	done := make(chan struct{})
	<-done
}

func initListener(logger log.Logger, host string, port int) net.Listener {
	on := host + ":" + strconv.FormatInt(int64(port), 10)
	listener, err := net.Listen("tcp", on)
	if err != nil {
		sklog.Fatal(logger, err)
	}
	return listener
}
<|endoftext|>