<commit_before>// Copyright 2017 Sorint.lab
//
// 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"
	"os"
	"path/filepath"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/sorintlab/stolon/internal/common"
	"github.com/sorintlab/stolon/internal/store"
	"github.com/sorintlab/stolon/internal/util"

	"github.com/mattn/go-isatty"
	"github.com/spf13/cobra"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth"
)

type CommonConfig struct {
	IsStolonCtl bool

	StoreBackend         string
	StoreEndpoints       string
	StorePrefix          string
	StoreCertFile        string
	StoreKeyFile         string
	StoreCAFile          string
	StoreSkipTlsVerify   bool
	ClusterName          string
	MetricsListenAddress string
	LogColor             bool
	LogLevel             string
	Debug                bool
	KubeResourceKind     string
	KubeConfig           string
	KubeContext          string
	KubeNamespace        string
}

func AddCommonFlags(cmd *cobra.Command, cfg *CommonConfig) {
	cmd.PersistentFlags().StringVar(&cfg.ClusterName, "cluster-name", "", "cluster name")
	cmd.PersistentFlags().StringVar(&cfg.StoreBackend, "store-backend", "", "store backend type (etcdv2/etcd, etcdv3, consul or kubernetes)")
	cmd.PersistentFlags().StringVar(&cfg.StoreEndpoints, "store-endpoints", "", "a comma-delimited list of store endpoints (use https scheme for tls communication) (defaults: http://127.0.0.1:2379 for etcd, http://127.0.0.1:8500 for consul)")
	cmd.PersistentFlags().StringVar(&cfg.StorePrefix, "store-prefix", common.StorePrefix, "the store base prefix")
	cmd.PersistentFlags().StringVar(&cfg.StoreCertFile, "store-cert-file", "", "certificate file for client identification to the store")
	cmd.PersistentFlags().StringVar(&cfg.StoreKeyFile, "store-key", "", "private key file for client identification to the store")
	cmd.PersistentFlags().BoolVar(&cfg.StoreSkipTlsVerify, "store-skip-tls-verify", false, "skip store certificate verification (insecure!!!)")
	cmd.PersistentFlags().StringVar(&cfg.StoreCAFile, "store-ca-file", "", "verify certificates of HTTPS-enabled store servers using this CA bundle")
	cmd.PersistentFlags().StringVar(&cfg.MetricsListenAddress, "metrics-listen-address", "", "metrics listen address i.e \"0.0.0.0:8080\" (disabled by default)")
	cmd.PersistentFlags().StringVar(&cfg.KubeResourceKind, "kube-resource-kind", "", `the k8s resource kind to be used to store stolon clusterdata and do sentinel leader election (only "configmap" is currently supported)`)

	if !cfg.IsStolonCtl {
		cmd.PersistentFlags().BoolVar(&cfg.LogColor, "log-color", false, "enable color in log output (default if attached to a terminal)")
		cmd.PersistentFlags().StringVar(&cfg.LogLevel, "log-level", "info", "debug, info (default), warn or error")
	}

	if cfg.IsStolonCtl {
		cmd.PersistentFlags().StringVar(&cfg.LogLevel, "log-level", "info", "debug, info (default), warn or error")
		cmd.PersistentFlags().StringVar(&cfg.KubeConfig, "kubeconfig", "", "path to kubeconfig file. Overrides $KUBECONFIG")
		cmd.PersistentFlags().StringVar(&cfg.KubeContext, "kube-context", "", "name of the kubeconfig context to use")
		cmd.PersistentFlags().StringVar(&cfg.KubeNamespace, "kube-namespace", "", "name of the kubernetes namespace to use")
	}
}

var (
	// clusterIdentifier provides a Prometheus metric that should uniquely identify the
	// cluster that any stolon component is associated with. Users can then join between
	// various metric series for the same cluster without making assumptions about service
	// discovery labels.
	clusterIdentifier = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "stolon_cluster_identifier",
			Help: "Set to 1, is labelled with the cluster_name",
		},
		[]string{"cluster_name"},
	)
)

func init() {
	prometheus.MustRegister(clusterIdentifier)
}

func CheckCommonConfig(cfg *CommonConfig) error {
	if cfg.ClusterName == "" {
		return fmt.Errorf("cluster name required")
	}
	if cfg.StoreBackend == "" {
		return fmt.Errorf("store backend type required")
	}

	switch cfg.StoreBackend {
	case "consul":
	case "etcd":
		// etcd is old alias for etcdv2
		cfg.StoreBackend = "etcdv2"
	case "etcdv2":
	case "etcdv3":
	case "kubernetes":
		if cfg.KubeResourceKind == "" {
			return fmt.Errorf("unspecified kubernetes resource kind")
		}
		if cfg.KubeResourceKind != "configmap" {
			return fmt.Errorf("wrong kubernetes resource kind: %q", cfg.KubeResourceKind)
		}
	default:
		return fmt.Errorf("Unknown store backend: %q", cfg.StoreBackend)
	}

	return nil
}

// SetMetrics should be called by any stolon component that outputs application metrics.
// It sets the clusterIdentifier metric, which is key to joining across all the other
// metric series.
func SetMetrics(cfg *CommonConfig) {
	clusterIdentifier.WithLabelValues(cfg.ClusterName).Set(1)
}

func IsColorLoggerEnable(cmd *cobra.Command, cfg *CommonConfig) bool {
	if cmd.PersistentFlags().Changed("log-color") {
		return cfg.LogColor
	} else {
		return isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())
	}
}

func NewKVStore(cfg *CommonConfig) (store.KVStore, error) {
	return store.NewKVStore(store.Config{
		Backend:       store.Backend(cfg.StoreBackend),
		Endpoints:     cfg.StoreEndpoints,
		CertFile:      cfg.StoreCertFile,
		KeyFile:       cfg.StoreKeyFile,
		CAFile:        cfg.StoreCAFile,
		SkipTLSVerify: cfg.StoreSkipTlsVerify,
	})
}

func NewStore(cfg *CommonConfig) (store.Store, error) {
	var s store.Store

	switch cfg.StoreBackend {
	case "consul":
		fallthrough
	case "etcdv2":
		fallthrough
	case "etcdv3":
		storePath := filepath.Join(cfg.StorePrefix, cfg.ClusterName)

		kvstore, err := NewKVStore(cfg)
		if err != nil {
			return nil, fmt.Errorf("cannot create kv store: %v", err)
		}
		s = store.NewKVBackedStore(kvstore, storePath)
	case "kubernetes":
		kubecli, podName, namespace, err := getKubeValues(cfg)
		if err != nil {
			return nil, err
		}
		s, err = store.NewKubeStore(kubecli, podName, namespace, cfg.ClusterName)
		if err != nil {
			return nil, fmt.Errorf("cannot create store: %v", err)
		}
	}

	return s, nil
}

func NewElection(cfg *CommonConfig, uid string) (store.Election, error) {
	var election store.Election

	switch cfg.StoreBackend {
	case "consul":
		fallthrough
	case "etcdv2":
		fallthrough
	case "etcdv3":
		storePath := filepath.Join(cfg.StorePrefix, cfg.ClusterName)

		kvstore, err := NewKVStore(cfg)
		if err != nil {
			return nil, fmt.Errorf("cannot create kv store: %v", err)
		}
		election = store.NewKVBackedElection(kvstore, filepath.Join(storePath, common.SentinelLeaderKey), uid)
	case "kubernetes":
		kubecli, podName, namespace, err := getKubeValues(cfg)
		if err != nil {
			return nil, err
		}
		election, err = store.NewKubeElection(kubecli, podName, namespace, cfg.ClusterName, uid)
		if err != nil {
			return nil, err
		}
	}

	return election, nil
}

func getKubeValues(cfg *CommonConfig) (*kubernetes.Clientset, string, string, error) {
	kubeClientConfig := util.NewKubeClientConfig(cfg.KubeConfig, cfg.KubeContext, cfg.KubeNamespace)
	kubecfg, err := kubeClientConfig.ClientConfig()
	if err != nil {
		return nil, "", "", err
	}
	kubecli, err := kubernetes.NewForConfig(kubecfg)
	if err != nil {
		return nil, "", "", fmt.Errorf("cannot create kubernetes client: %v", err)
	}
	var podName string
	if !cfg.IsStolonCtl {
		podName, err = util.PodName()
		if err != nil {
			return nil, "", "", err
		}
	}
	namespace, _, err := kubeClientConfig.Namespace()
	if err != nil {
		return nil, "", "", err
	}
	return kubecli, podName, namespace, nil
}
<commit_msg>Add timeout for kube client<commit_after>// Copyright 2017 Sorint.lab
//
// 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"
	"os"
	"path/filepath"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/sorintlab/stolon/internal/cluster"
	"github.com/sorintlab/stolon/internal/common"
	"github.com/sorintlab/stolon/internal/store"
	"github.com/sorintlab/stolon/internal/util"

	"github.com/mattn/go-isatty"
	"github.com/spf13/cobra"
	"k8s.io/client-go/kubernetes"
	_ "k8s.io/client-go/plugin/pkg/client/auth"
)

type CommonConfig struct {
	IsStolonCtl bool

	StoreBackend         string
	StoreEndpoints       string
	StorePrefix          string
	StoreCertFile        string
	StoreKeyFile         string
	StoreCAFile          string
	StoreSkipTlsVerify   bool
	ClusterName          string
	MetricsListenAddress string
	LogColor             bool
	LogLevel             string
	Debug                bool
	KubeResourceKind     string
	KubeConfig           string
	KubeContext          string
	KubeNamespace        string
}

func AddCommonFlags(cmd *cobra.Command, cfg *CommonConfig) {
	cmd.PersistentFlags().StringVar(&cfg.ClusterName, "cluster-name", "", "cluster name")
	cmd.PersistentFlags().StringVar(&cfg.StoreBackend, "store-backend", "", "store backend type (etcdv2/etcd, etcdv3, consul or kubernetes)")
	cmd.PersistentFlags().StringVar(&cfg.StoreEndpoints, "store-endpoints", "", "a comma-delimited list of store endpoints (use https scheme for tls communication) (defaults: http://127.0.0.1:2379 for etcd, http://127.0.0.1:8500 for consul)")
	cmd.PersistentFlags().StringVar(&cfg.StorePrefix, "store-prefix", common.StorePrefix, "the store base prefix")
	cmd.PersistentFlags().StringVar(&cfg.StoreCertFile, "store-cert-file", "", "certificate file for client identification to the store")
	cmd.PersistentFlags().StringVar(&cfg.StoreKeyFile, "store-key", "", "private key file for client identification to the store")
	cmd.PersistentFlags().BoolVar(&cfg.StoreSkipTlsVerify, "store-skip-tls-verify", false, "skip store certificate verification (insecure!!!)")
	cmd.PersistentFlags().StringVar(&cfg.StoreCAFile, "store-ca-file", "", "verify certificates of HTTPS-enabled store servers using this CA bundle")
	cmd.PersistentFlags().StringVar(&cfg.MetricsListenAddress, "metrics-listen-address", "", "metrics listen address i.e \"0.0.0.0:8080\" (disabled by default)")
	cmd.PersistentFlags().StringVar(&cfg.KubeResourceKind, "kube-resource-kind", "", `the k8s resource kind to be used to store stolon clusterdata and do sentinel leader election (only "configmap" is currently supported)`)

	if !cfg.IsStolonCtl {
		cmd.PersistentFlags().BoolVar(&cfg.LogColor, "log-color", false, "enable color in log output (default if attached to a terminal)")
		cmd.PersistentFlags().StringVar(&cfg.LogLevel, "log-level", "info", "debug, info (default), warn or error")
	}

	if cfg.IsStolonCtl {
		cmd.PersistentFlags().StringVar(&cfg.LogLevel, "log-level", "info", "debug, info (default), warn or error")
		cmd.PersistentFlags().StringVar(&cfg.KubeConfig, "kubeconfig", "", "path to kubeconfig file. Overrides $KUBECONFIG")
		cmd.PersistentFlags().StringVar(&cfg.KubeContext, "kube-context", "", "name of the kubeconfig context to use")
		cmd.PersistentFlags().StringVar(&cfg.KubeNamespace, "kube-namespace", "", "name of the kubernetes namespace to use")
	}
}

var (
	// clusterIdentifier provides a Prometheus metric that should uniquely identify the
	// cluster that any stolon component is associated with. Users can then join between
	// various metric series for the same cluster without making assumptions about service
	// discovery labels.
	clusterIdentifier = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name: "stolon_cluster_identifier",
			Help: "Set to 1, is labelled with the cluster_name",
		},
		[]string{"cluster_name"},
	)
)

func init() {
	prometheus.MustRegister(clusterIdentifier)
}

func CheckCommonConfig(cfg *CommonConfig) error {
	if cfg.ClusterName == "" {
		return fmt.Errorf("cluster name required")
	}
	if cfg.StoreBackend == "" {
		return fmt.Errorf("store backend type required")
	}

	switch cfg.StoreBackend {
	case "consul":
	case "etcd":
		// etcd is old alias for etcdv2
		cfg.StoreBackend = "etcdv2"
	case "etcdv2":
	case "etcdv3":
	case "kubernetes":
		if cfg.KubeResourceKind == "" {
			return fmt.Errorf("unspecified kubernetes resource kind")
		}
		if cfg.KubeResourceKind != "configmap" {
			return fmt.Errorf("wrong kubernetes resource kind: %q", cfg.KubeResourceKind)
		}
	default:
		return fmt.Errorf("Unknown store backend: %q", cfg.StoreBackend)
	}

	return nil
}

// SetMetrics should be called by any stolon component that outputs application metrics.
// It sets the clusterIdentifier metric, which is key to joining across all the other
// metric series.
func SetMetrics(cfg *CommonConfig) {
	clusterIdentifier.WithLabelValues(cfg.ClusterName).Set(1)
}

func IsColorLoggerEnable(cmd *cobra.Command, cfg *CommonConfig) bool {
	if cmd.PersistentFlags().Changed("log-color") {
		return cfg.LogColor
	} else {
		return isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())
	}
}

func NewKVStore(cfg *CommonConfig) (store.KVStore, error) {
	return store.NewKVStore(store.Config{
		Backend:       store.Backend(cfg.StoreBackend),
		Endpoints:     cfg.StoreEndpoints,
		CertFile:      cfg.StoreCertFile,
		KeyFile:       cfg.StoreKeyFile,
		CAFile:        cfg.StoreCAFile,
		SkipTLSVerify: cfg.StoreSkipTlsVerify,
	})
}

func NewStore(cfg *CommonConfig) (store.Store, error) {
	var s store.Store

	switch cfg.StoreBackend {
	case "consul":
		fallthrough
	case "etcdv2":
		fallthrough
	case "etcdv3":
		storePath := filepath.Join(cfg.StorePrefix, cfg.ClusterName)

		kvstore, err := NewKVStore(cfg)
		if err != nil {
			return nil, fmt.Errorf("cannot create kv store: %v", err)
		}
		s = store.NewKVBackedStore(kvstore, storePath)
	case "kubernetes":
		kubecli, podName, namespace, err := getKubeValues(cfg)
		if err != nil {
			return nil, err
		}
		s, err = store.NewKubeStore(kubecli, podName, namespace, cfg.ClusterName)
		if err != nil {
			return nil, fmt.Errorf("cannot create store: %v", err)
		}
	}

	return s, nil
}

func NewElection(cfg *CommonConfig, uid string) (store.Election, error) {
	var election store.Election

	switch cfg.StoreBackend {
	case "consul":
		fallthrough
	case "etcdv2":
		fallthrough
	case "etcdv3":
		storePath := filepath.Join(cfg.StorePrefix, cfg.ClusterName)

		kvstore, err := NewKVStore(cfg)
		if err != nil {
			return nil, fmt.Errorf("cannot create kv store: %v", err)
		}
		election = store.NewKVBackedElection(kvstore, filepath.Join(storePath, common.SentinelLeaderKey), uid)
	case "kubernetes":
		kubecli, podName, namespace, err := getKubeValues(cfg)
		if err != nil {
			return nil, err
		}
		election, err = store.NewKubeElection(kubecli, podName, namespace, cfg.ClusterName, uid)
		if err != nil {
			return nil, err
		}
	}

	return election, nil
}

func getKubeValues(cfg *CommonConfig) (*kubernetes.Clientset, string, string, error) {
	kubeClientConfig := util.NewKubeClientConfig(cfg.KubeConfig, cfg.KubeContext, cfg.KubeNamespace)
	kubecfg, err := kubeClientConfig.ClientConfig()
	if err != nil {
		return nil, "", "", err
	}
	kubecfg.Timeout = cluster.DefaultStoreTimeout
	kubecli, err := kubernetes.NewForConfig(kubecfg)
	if err != nil {
		return nil, "", "", fmt.Errorf("cannot create kubernetes client: %v", err)
	}
	var podName string
	if !cfg.IsStolonCtl {
		podName, err = util.PodName()
		if err != nil {
			return nil, "", "", err
		}
	}
	namespace, _, err := kubeClientConfig.Namespace()
	if err != nil {
		return nil, "", "", err
	}
	return kubecli, podName, namespace, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"encoding/json"
	nerrors "errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/errors"
	"github.com/filebrowser/filebrowser/v2/settings"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func init() {
	rootCmd.AddCommand(configCmd)
}

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Configuration management utility",
	Long:  `Configuration management utility.`,
	Args:  cobra.NoArgs,
}

func addConfigFlags(flags *pflag.FlagSet) {
	addServerFlags(flags)
	addUserFlags(flags)
	flags.BoolP("signup", "s", false, "allow users to signup")
	flags.String("shell", "", "shell command to which other commands should be appended")

	flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
	flags.String("auth.header", "", "HTTP header for auth.method=proxy")

	flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
	flags.String("recaptcha.key", "", "ReCaptcha site key")
	flags.String("recaptcha.secret", "", "ReCaptcha secret")

	flags.String("branding.name", "", "replace 'File Browser' by this name")
	flags.String("branding.files", "", "path to directory with images and custom styles")
	flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
}

func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther) {
	method := settings.AuthMethod(mustGetString(flags, "auth.method"))

	var defaultAuther map[string]interface{}
	if len(defaults) > 0 {
		if hasAuth := defaults[0]; hasAuth != true {
			for _, arg := range defaults {
				switch def := arg.(type) {
				case *settings.Settings:
					method = settings.AuthMethod(def.AuthMethod)
				case auth.Auther:
					ms, err := json.Marshal(def)
					checkErr(err)
					json.Unmarshal(ms, &defaultAuther)
				}
			}
		}
	}

	var auther auth.Auther
	if method == auth.MethodProxyAuth {
		header := mustGetString(flags, "auth.header")

		if header == "" {
			header = defaultAuther["header"].(string)
		}

		if header == "" {
			panic(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
		}

		auther = &auth.ProxyAuth{Header: header}
	}

	if method == auth.MethodNoAuth {
		auther = &auth.NoAuth{}
	}

	if method == auth.MethodJSONAuth {
		jsonAuth := &auth.JSONAuth{}
		host := mustGetString(flags, "recaptcha.host")
		key := mustGetString(flags, "recaptcha.key")
		secret := mustGetString(flags, "recaptcha.secret")

		if key == "" {
			kmap := defaultAuther["recaptcha"].(map[string]interface{})
			key = kmap["key"].(string)
		}

		if secret == "" {
			smap := defaultAuther["recaptcha"].(map[string]interface{})
			secret = smap["secret"].(string)
		}

		if key == "" || secret == "" {
			panic(nerrors.New("you must set the flag 'recaptcha.key' and 'recaptcha.secret' for method 'json'"))
		}

		jsonAuth.ReCaptcha = &auth.ReCaptcha{
			Host:   host,
			Key:    key,
			Secret: secret,
		}

		auther = jsonAuth
	}

	if auther == nil {
		panic(errors.ErrInvalidAuthMethod)
	}

	return method, auther
}

func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
	fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
	fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
	fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
	fmt.Fprintln(w, "\nBranding:")
	fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
	fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
	fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
	fmt.Fprintln(w, "\nServer:")
	fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
	fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
	fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
	fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
	fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
	fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
	fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
	fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
	fmt.Fprintln(w, "\nDefaults:")
	fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
	fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
	fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
	fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
	fmt.Fprintf(w, "\tSorting:\n")
	fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
	fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
	fmt.Fprintf(w, "\tPermissions:\n")
	fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
	fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
	fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
	fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
	fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
	fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
	fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
	fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
	w.Flush()

	b, err := json.MarshalIndent(auther, "", "  ")
	checkErr(err)
	fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
}
<commit_msg>Fix panic with checkerr<commit_after>package cmd

import (
	"encoding/json"
	nerrors "errors"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/filebrowser/filebrowser/v2/auth"
	"github.com/filebrowser/filebrowser/v2/errors"
	"github.com/filebrowser/filebrowser/v2/settings"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

func init() {
	rootCmd.AddCommand(configCmd)
}

var configCmd = &cobra.Command{
	Use:   "config",
	Short: "Configuration management utility",
	Long:  `Configuration management utility.`,
	Args:  cobra.NoArgs,
}

func addConfigFlags(flags *pflag.FlagSet) {
	addServerFlags(flags)
	addUserFlags(flags)
	flags.BoolP("signup", "s", false, "allow users to signup")
	flags.String("shell", "", "shell command to which other commands should be appended")

	flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
	flags.String("auth.header", "", "HTTP header for auth.method=proxy")

	flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
	flags.String("recaptcha.key", "", "ReCaptcha site key")
	flags.String("recaptcha.secret", "", "ReCaptcha secret")

	flags.String("branding.name", "", "replace 'File Browser' by this name")
	flags.String("branding.files", "", "path to directory with images and custom styles")
	flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
}

func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, auth.Auther) {
	method := settings.AuthMethod(mustGetString(flags, "auth.method"))

	var defaultAuther map[string]interface{}
	if len(defaults) > 0 {
		if hasAuth := defaults[0]; hasAuth != true {
			for _, arg := range defaults {
				switch def := arg.(type) {
				case *settings.Settings:
					method = settings.AuthMethod(def.AuthMethod)
				case auth.Auther:
					ms, err := json.Marshal(def)
					checkErr(err)
					json.Unmarshal(ms, &defaultAuther)
				}
			}
		}
	}

	var auther auth.Auther
	if method == auth.MethodProxyAuth {
		header := mustGetString(flags, "auth.header")

		if header == "" {
			header = defaultAuther["header"].(string)
		}

		if header == "" {
			checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
		}

		auther = &auth.ProxyAuth{Header: header}
	}

	if method == auth.MethodNoAuth {
		auther = &auth.NoAuth{}
	}

	if method == auth.MethodJSONAuth {
		jsonAuth := &auth.JSONAuth{}
		host := mustGetString(flags, "recaptcha.host")
		key := mustGetString(flags, "recaptcha.key")
		secret := mustGetString(flags, "recaptcha.secret")

		if key == "" {
			kmap := defaultAuther["recaptcha"].(map[string]interface{})
			key = kmap["key"].(string)
		}

		if secret == "" {
			smap := defaultAuther["recaptcha"].(map[string]interface{})
			secret = smap["secret"].(string)
		}

		if key == "" || secret == "" {
			checkErr(nerrors.New("you must set the flag 'recaptcha.key' and 'recaptcha.secret' for method 'json'"))
		}

		jsonAuth.ReCaptcha = &auth.ReCaptcha{
			Host:   host,
			Key:    key,
			Secret: secret,
		}

		auther = jsonAuth
	}

	if auther == nil {
		panic(errors.ErrInvalidAuthMethod)
	}

	return method, auther
}

func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)

	fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
	fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
	fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
	fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
	fmt.Fprintln(w, "\nBranding:")
	fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
	fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
	fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
	fmt.Fprintln(w, "\nServer:")
	fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
	fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
	fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
	fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
	fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
	fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
	fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
	fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
	fmt.Fprintln(w, "\nDefaults:")
	fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
	fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
	fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
	fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
	fmt.Fprintf(w, "\tSorting:\n")
	fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
	fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
	fmt.Fprintf(w, "\tPermissions:\n")
	fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
	fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
	fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
	fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
	fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
	fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
	fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
	fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
	w.Flush()

	b, err := json.MarshalIndent(auther, "", "  ")
	checkErr(err)
	fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
}
<|endoftext|>


<commit_before>package cmd

import (
	"os"

	"chkit-v2/chlib"
	"chkit-v2/helpers"

	"strings"

	"regexp"

	"github.com/spf13/cobra"
)

var deleteCmdKind, deleteCmdFile, deleteCmdName string

var deleteCmd = &cobra.Command{
	Use:        "delete (KIND NAME| --file -f FILE)",
	Short:      "Remove object from namespace",
	ValidArgs:  []string{chlib.KindPods, chlib.KindDeployments, chlib.KindNamespaces, chlib.KindService, "--file", "-f"},
	ArgAliases: []string{"po", "pods", "pod", "deployments", "deployment", "deploy", "service", "services", "svc", "ns", "namespaces", "namespace"},
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			np.FEEDBACK.Println("KIND or file not specified")
			cmd.Usage()
			os.Exit(1)
		}
		switch args[0] {
		case "po", "pods", "pod":
			deleteCmdKind = chlib.KindPods
		case "deployments", "deployment", "deploy":
			deleteCmdKind = chlib.KindDeployments
		case "service", "services", "svc":
			deleteCmdKind = chlib.KindService
		case "ns", "namespaces", "namespace":
			deleteCmdKind = chlib.KindNamespaces
		default:
			if cmd.Flag("file").Changed {
				deleteCmdFile, _ = cmd.Flags().GetString("file")
			} else {
				np.FEEDBACK.Printf("Invalid KIND. Choose from (%s)\n", strings.Join(cmd.ArgAliases, ", "))
				cmd.Usage()
				os.Exit(1)
			}
		}
		if len(args) >= 2 && deleteCmdFile == "" && regexp.MustCompile(chlib.ObjectNameRegex).MatchString(args[1]) {
			deleteCmdName = args[1]
		} else {
			np.FEEDBACK.Println("NAME is not specified or invalid")
			cmd.Usage()
			os.Exit(1)
		}
		if deleteCmdFile != "" {
			var obj chlib.CommonObject
			err := chlib.LoadJsonFromFile(deleteCmdFile, &obj)
			if err != nil {
				np.ERROR.Println(err)
				os.Exit(1)
			}
			deleteCmdKind = obj.Kind
			deleteCmdName = obj.Metadata.Name
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		client, err := chlib.NewClient(db, helpers.CurrentClientVersion, helpers.UuidV4(), np)
		if err != nil {
			np.ERROR.Println(err)
			return
		}
		nameSpace, _ := cmd.Flags().GetString("namespace")
		np.FEEDBACK.Print("delete...")
		_, err = client.Delete(deleteCmdKind, deleteCmdName, nameSpace, false)
		if err != nil {
			np.FEEDBACK.Println("ERROR")
			np.ERROR.Println(err)
		} else {
			np.FEEDBACK.Println("OK")
		}
	},
}

func init() {
	deleteCmd.PersistentFlags().StringP("file", "f", "", "File generated at object creation")
	cobra.MarkFlagFilename(deleteCmd.PersistentFlags(), "file", "json")
	deleteCmd.PersistentFlags().StringP("namespace", "n", "", "Namespace")
	cobra.MarkFlagCustom(deleteCmd.PersistentFlags(), "namespace", "__chkit_namespaces_list")
	RootCmd.AddCommand(deleteCmd)
}
<commit_msg>Add multiple object deleting<commit_after>package cmd

import (
	"os"

	"chkit-v2/chlib"
	"chkit-v2/helpers"

	"strings"

	"regexp"

	"github.com/spf13/cobra"
)

var deleteCmdKind, deleteCmdFile string
var deleteCmdNames []string

var deleteCmd = &cobra.Command{
	Use:        "delete (KIND NAME [NAME2]...| --file -f FILE)",
	Short:      "Remove object from namespace",
	ValidArgs:  []string{chlib.KindPods, chlib.KindDeployments, chlib.KindNamespaces, chlib.KindService, "--file", "-f"},
	ArgAliases: []string{"po", "pods", "pod", "deployments", "deployment", "deploy", "service", "services", "svc", "ns", "namespaces", "namespace"},
	PreRun: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			np.FEEDBACK.Println("KIND or file not specified")
			cmd.Usage()
			os.Exit(1)
		}
		switch args[0] {
		case "po", "pods", "pod":
			deleteCmdKind = chlib.KindPods
		case "deployments", "deployment", "deploy":
			deleteCmdKind = chlib.KindDeployments
		case "service", "services", "svc":
			deleteCmdKind = chlib.KindService
		case "ns", "namespaces", "namespace":
			deleteCmdKind = chlib.KindNamespaces
		default:
			if cmd.Flag("file").Changed {
				deleteCmdFile, _ = cmd.Flags().GetString("file")
			} else {
				np.FEEDBACK.Printf("Invalid KIND. Choose from (%s)\n", strings.Join(cmd.ArgAliases, ", "))
				cmd.Usage()
				os.Exit(1)
			}
		}
		if len(args) >= 2 && deleteCmdFile == "" {
			for _, v := range args[1:] {
				if !regexp.MustCompile(chlib.ObjectNameRegex).MatchString(v) {
					break
				}
				deleteCmdNames = append(deleteCmdNames, v)
			}
		} else {
			np.FEEDBACK.Println("NAME is not specified or invalid")
			cmd.Usage()
			os.Exit(1)
		}
		if deleteCmdFile != "" {
			var obj chlib.CommonObject
			err := chlib.LoadJsonFromFile(deleteCmdFile, &obj)
			if err != nil {
				np.ERROR.Println(err)
				os.Exit(1)
			}
			deleteCmdKind = obj.Kind
			deleteCmdNames = []string{obj.Metadata.Name}
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		client, err := chlib.NewClient(db, helpers.CurrentClientVersion, helpers.UuidV4(), np)
		if err != nil {
			np.ERROR.Println(err)
			return
		}
		nameSpace, _ := cmd.Flags().GetString("namespace")
		for _, deleteCmdName := range deleteCmdNames {
			np.FEEDBACK.Printf("delete %s...", deleteCmdName)
			_, err = client.Delete(deleteCmdKind, deleteCmdName, nameSpace, false)
			if err != nil {
				np.FEEDBACK.Println("ERROR")
				np.ERROR.Println(err)
				return
			} else {
				np.FEEDBACK.Println("OK")
			}
		}
	},
}

func init() {
	deleteCmd.PersistentFlags().StringP("file", "f", "", "File generated at object creation")
	cobra.MarkFlagFilename(deleteCmd.PersistentFlags(), "file", "json")
	deleteCmd.PersistentFlags().StringP("namespace", "n", "", "Namespace")
	cobra.MarkFlagCustom(deleteCmd.PersistentFlags(), "namespace", "__chkit_namespaces_list")
	RootCmd.AddCommand(deleteCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/cli/monitor"
	"github.com/rancher/go-rancher/v2"
	"github.com/urfave/cli"
)

func EventsCommand() cli.Command {
	return cli.Command{
		Name:        "events",
		Usage:       "Displays resource change events",
		Description: "\nOnly events that are actively occuring in Rancher are listed.\n",
		ArgsUsage:   "None",
		Action:      events,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "format",
				Usage: "'json' or Custom format: {{.Id}} {{.Name}}",
			},
			cli.BoolFlag{
				Name:  "reconnect,r",
				Usage: "Reconnect on error",
			},
		},
	}
}

func getClientForSubscribe(ctx *cli.Context) (*client.RancherClient, error) {
	if ctx.Bool("all") {
		return GetRawClient(ctx)
	}
	return GetClient(ctx)
}

func events(ctx *cli.Context) error {
	reconnect := ctx.Bool("reconnect")

	for {
		c, err := getClientForSubscribe(ctx)
		if err != nil {
			if reconnect {
				logrus.Error(err)
				time.Sleep(time.Second)
				continue
			} else {
				return err
			}
		}

		m := monitor.New(c)
		sub := m.Subscribe()
		go func() {
			if ctx.Bool("reconnect") {
				for {
					if err := m.Start(); err != nil {
						logrus.Error(err)
					}
					time.Sleep(time.Second)
				}
			} else {
				logrus.Fatal(m.Start())
			}
		}()

		format := ctx.String("format")
		for event := range sub.C {
			if format == "" {
				resource, _ := event.Data["resource"].(map[string]interface{})
				name, _ := resource["name"].(string)
				state, _ := resource["state"].(string)

				if name == "ping" {
					continue
				}

				message, _ := resource["transitioningMessage"].(string)
				fmt.Printf("%s %s %s [%s] %v\n", event.ResourceType, event.ResourceID, state, name, message)
			} else {
				writer := NewTableWriter(nil, ctx)
				writer.Write(event)
				if err := writer.Err(); err != nil {
					logrus.Error(err)
				}
			}
		}
	}
}
<commit_msg>Show combined status for events<commit_after>package cmd

import (
	"fmt"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/rancher/cli/monitor"
	"github.com/rancher/go-rancher/v2"
	"github.com/urfave/cli"
)

func EventsCommand() cli.Command {
	return cli.Command{
		Name:        "events",
		Usage:       "Displays resource change events",
		Description: "\nOnly events that are actively occuring in Rancher are listed.\n",
		ArgsUsage:   "None",
		Action:      events,
		Flags: []cli.Flag{
			cli.StringFlag{
				Name:  "format",
				Usage: "'json' or Custom format: {{.Id}} {{.Name}}",
			},
			cli.BoolFlag{
				Name:  "reconnect,r",
				Usage: "Reconnect on error",
			},
		},
	}
}

func getClientForSubscribe(ctx *cli.Context) (*client.RancherClient, error) {
	if ctx.Bool("all") {
		return GetRawClient(ctx)
	}
	return GetClient(ctx)
}

func events(ctx *cli.Context) error {
	reconnect := ctx.Bool("reconnect")

	for {
		c, err := getClientForSubscribe(ctx)
		if err != nil {
			if reconnect {
				logrus.Error(err)
				time.Sleep(time.Second)
				continue
			} else {
				return err
			}
		}

		m := monitor.New(c)
		sub := m.Subscribe()
		go func() {
			if ctx.Bool("reconnect") {
				for {
					if err := m.Start(); err != nil {
						logrus.Error(err)
					}
					time.Sleep(time.Second)
				}
			} else {
				logrus.Fatal(m.Start())
			}
		}()

		format := ctx.String("format")
		for event := range sub.C {
			if format == "" {
				resource, _ := event.Data["resource"].(map[string]interface{})
				name, _ := resource["name"].(string)

				if name == "ping" {
					continue
				}

				healthState, _ := resource["healthState"].(string)
				state, _ := resource["state"].(string)

				combined := healthState
				if state != "active" || combined == "" {
					combined = state
				}

				message, _ := resource["transitioningMessage"].(string)
				fmt.Printf("%s %s %s [%s] %v\n", event.ResourceType, event.ResourceID, combined, name, message)
			} else {
				writer := NewTableWriter(nil, ctx)
				writer.Write(event)
				if err := writer.Err(); err != nil {
					logrus.Error(err)
				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Pilosa Corp.
//
// 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 (
	"context"
	"io"
	"os"

	"github.com/spf13/cobra"

	"github.com/pilosa/pilosa/ctl"
)

var Exporter *ctl.ExportCommand

func NewExportCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
	Exporter = ctl.NewExportCommand(os.Stdin, os.Stdout, os.Stderr)
	exportCmd := &cobra.Command{
		Use:   "export",
		Short: "Export data from pilosa.",
		Long: `
Bulk exports a fragment to a CSV file. If the OUTFILE is not specified then
the output is written to STDOUT.

The format of the CSV file is:

	ROWID,COLUMNID

The file does not contain any headers.
`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := Exporter.Run(context.Background()); err != nil {
				return err
			}
			return nil
		},
	}
	flags := exportCmd.Flags()

	flags.StringVarP(&Exporter.Host, "host", "", "localhost:10101", "host:port of Pilosa.")
	flags.StringVarP(&Exporter.Index, "index", "i", "", "Pilosa index to export")
	flags.StringVarP(&Exporter.Field, "field", "f", "", "Field to export")
	flags.StringVarP(&Exporter.Path, "output-file", "o", "", "File to write export to - default stdout")
	ctl.SetTLSConfig(flags, &Exporter.TLS.CertificatePath, &Exporter.TLS.CertificateKeyPath, &Exporter.TLS.SkipVerify)

	return exportCmd
}

func init() {
	subcommandFns["export"] = NewExportCommand
}
<commit_msg>Unexport cmd.NewExportCommand<commit_after>// Copyright 2017 Pilosa Corp.
//
// 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 (
	"context"
	"io"
	"os"

	"github.com/spf13/cobra"

	"github.com/pilosa/pilosa/ctl"
)

var Exporter *ctl.ExportCommand

func newExportCommand(stdin io.Reader, stdout, stderr io.Writer) *cobra.Command {
	Exporter = ctl.NewExportCommand(os.Stdin, os.Stdout, os.Stderr)
	exportCmd := &cobra.Command{
		Use:   "export",
		Short: "Export data from pilosa.",
		Long: `
Bulk exports a fragment to a CSV file. If the OUTFILE is not specified then
the output is written to STDOUT.

The format of the CSV file is:

	ROWID,COLUMNID

The file does not contain any headers.
`,
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := Exporter.Run(context.Background()); err != nil {
				return err
			}
			return nil
		},
	}
	flags := exportCmd.Flags()

	flags.StringVarP(&Exporter.Host, "host", "", "localhost:10101", "host:port of Pilosa.")
	flags.StringVarP(&Exporter.Index, "index", "i", "", "Pilosa index to export")
	flags.StringVarP(&Exporter.Field, "field", "f", "", "Field to export")
	flags.StringVarP(&Exporter.Path, "output-file", "o", "", "File to write export to - default stdout")
	ctl.SetTLSConfig(flags, &Exporter.TLS.CertificatePath, &Exporter.TLS.CertificateKeyPath, &Exporter.TLS.SkipVerify)

	return exportCmd
}

func init() {
	subcommandFns["export"] = newExportCommand
}
<|endoftext|>


<commit_before>package cmd

import (
	"github.com/spf13/cobra"
	"github.com/tsaikd/KDGoLib/cliutil/cobrather"
	"github.com/tsaikd/gobuilder/cmd/modBuild"
	"github.com/tsaikd/gobuilder/cmd/modCheckError"
	"github.com/tsaikd/gobuilder/cmd/modCheckFmt"
	"github.com/tsaikd/gobuilder/cmd/modCheckRedundant"
	"github.com/tsaikd/gobuilder/cmd/modDep"
	"github.com/tsaikd/gobuilder/cmd/modFlags"
	"github.com/tsaikd/gobuilder/cmd/modGet"
	"github.com/tsaikd/gobuilder/cmd/modRestore"
	"github.com/tsaikd/gobuilder/cmd/modTest"
)

// command line flags
var (
	flagCheck = &cobrather.BoolFlag{
		Name:      "check",
		ShortHand: "c",
		Default:   false,
		Usage:     "Add check actions in building chain: checkerror -> checkfmt -> [BUILD ACTIONS] -> checkredundant",
	}
)

// Module info
var Module = &cobrather.Module{
	Use:   "gobuilder",
	Short: "Go application builder, run action: restore -> get -> build -> test",
	Commands: []*cobrather.Module{
		modDep.Module,
		modCheckError.Module,
		modCheckFmt.Module,
		modCheckRedundant.Module,
		modRestore.Module,
		modGet.Module,
		modBuild.Module,
		modTest.Module,
		cobrather.VersionModule,
	},
	Dependencies: []*cobrather.Module{
		modFlags.Module,
	},
	Flags: []cobrather.Flag{
		flagCheck,
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		runFuncs := []func(cmd *cobra.Command, args []string) error{}

		cmdModules := []*cobrather.Module{}
		if flagCheck.Bool() {
			cmdModules = append(cmdModules,
				modCheckError.Module,
				modCheckFmt.Module,
			)
		}
		cmdModules = append(cmdModules,
			modRestore.Module,
			modGet.Module,
			modBuild.Module,
		)
		if modFlags.Test() {
			cmdModules = append(cmdModules, modTest.Module)
		}
		if flagCheck.Bool() {
			cmdModules = append(cmdModules, modCheckRedundant.Module)
		}

		depModules := cobrather.ListDeps(cobrather.OIncludeDepInCommand, cmdModules...)
		preRun := cobrather.GenRunE(depModules...)
		runFuncs = append(runFuncs, preRun)

		run := cobrather.GenRunE(cmdModules...)
		runFuncs = append(runFuncs, run)

		postRun := cobrather.GenPostRunE(cmdModules...)
		runFuncs = append(runFuncs, postRun)

		depPostRun := cobrather.GenPostRunE(depModules...)
		runFuncs = append(runFuncs, depPostRun)

		for _, fn := range runFuncs {
			if err := fn(cmd, args); err != nil {
				return err
			}
		}

		return nil
	},
}
<commit_msg>build action order changed: checkerror should be after build action to ensure all import path is valid<commit_after>package cmd

import (
	"github.com/spf13/cobra"
	"github.com/tsaikd/KDGoLib/cliutil/cobrather"
	"github.com/tsaikd/gobuilder/cmd/modBuild"
	"github.com/tsaikd/gobuilder/cmd/modCheckError"
	"github.com/tsaikd/gobuilder/cmd/modCheckFmt"
	"github.com/tsaikd/gobuilder/cmd/modCheckRedundant"
	"github.com/tsaikd/gobuilder/cmd/modDep"
	"github.com/tsaikd/gobuilder/cmd/modFlags"
	"github.com/tsaikd/gobuilder/cmd/modGet"
	"github.com/tsaikd/gobuilder/cmd/modRestore"
	"github.com/tsaikd/gobuilder/cmd/modTest"
)

// command line flags
var (
	flagCheck = &cobrather.BoolFlag{
		Name:      "check",
		ShortHand: "c",
		Default:   false,
		Usage:     "Add check actions in building chain: checkfmt -> <BUILD ACTIONS> -> checkerror -> checkredundant",
	}
)

// Module info
var Module = &cobrather.Module{
	Use:   "gobuilder",
	Short: "Go application builder, run action: restore -> get -> build -> [test]",
	Commands: []*cobrather.Module{
		modDep.Module,
		modCheckFmt.Module,
		modRestore.Module,
		modGet.Module,
		modBuild.Module,
		modTest.Module,
		modCheckError.Module,
		modCheckRedundant.Module,
		cobrather.VersionModule,
	},
	Dependencies: []*cobrather.Module{
		modFlags.Module,
	},
	Flags: []cobrather.Flag{
		flagCheck,
	},
	RunE: func(cmd *cobra.Command, args []string) error {
		runFuncs := []func(cmd *cobra.Command, args []string) error{}

		cmdModules := []*cobrather.Module{}
		if flagCheck.Bool() {
			cmdModules = append(cmdModules,
				modCheckFmt.Module,
			)
		}
		cmdModules = append(cmdModules,
			modRestore.Module,
			modGet.Module,
			modBuild.Module,
		)
		if modFlags.Test() {
			cmdModules = append(cmdModules,
				modTest.Module,
			)
		}
		if flagCheck.Bool() {
			cmdModules = append(cmdModules,
				modCheckError.Module,
				modCheckRedundant.Module,
			)
		}

		depModules := cobrather.ListDeps(cobrather.OIncludeDepInCommand, cmdModules...)
		preRun := cobrather.GenRunE(depModules...)
		runFuncs = append(runFuncs, preRun)

		run := cobrather.GenRunE(cmdModules...)
		runFuncs = append(runFuncs, run)

		postRun := cobrather.GenPostRunE(cmdModules...)
		runFuncs = append(runFuncs, postRun)

		depPostRun := cobrather.GenPostRunE(depModules...)
		runFuncs = append(runFuncs, depPostRun)

		for _, fn := range runFuncs {
			if err := fn(cmd, args); err != nil {
				return err
			}
		}

		return nil
	},
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"log/syslog"
	"os"
	"sync"
)

// derive logger
func getLogger(useSyslog bool) (logger io.Writer, err error) {
	if useSyslog {
		logger, err = syslog.New(syslog.LOG_DAEMON|syslog.LOG_NOTICE, monitoringEvent)
	} else {
		logger = os.Stderr
		log.SetPrefix(monitoringEvent + ": ")
	}
	if err == nil {
		log.SetOutput(logger)
	}
	return &LineWriter{w: logger}, err
}

// pipe r to logger in the background
func logStream(r io.Reader, logger io.Writer, wg *sync.WaitGroup) {
	wg.Add(1)

	go func() {
		// Retry writing to logstream until it can be fully written.
		// If io.Copy returns nil, everything has been copied
		// successfully and this routine can be stopped.
		for {
			if _, err := io.Copy(logger, r); err == nil {
				break
			}
		}
		wg.Done()
	}()
}
<commit_msg>Use syslog package from Go 1.2rc2<commit_after>package main

import (
	"io"
	"log"
	"os"
	"sync"

	"github.com/Jimdo/periodicnoise/syslog"
)

// derive logger
func getLogger(useSyslog bool) (logger io.Writer, err error) {
	if useSyslog {
		logger, err = syslog.New(syslog.LOG_DAEMON|syslog.LOG_NOTICE, monitoringEvent)
	} else {
		logger = os.Stderr
		log.SetPrefix(monitoringEvent + ": ")
	}
	if err == nil {
		log.SetOutput(logger)
	}
	return &LineWriter{w: logger}, err
}

// pipe r to logger in the background
func logStream(r io.Reader, logger io.Writer, wg *sync.WaitGroup) {
	wg.Add(1)

	go func() {
		// Retry writing to logstream until it can be fully written.
		// If io.Copy returns nil, everything has been copied
		// successfully and this routine can be stopped.
		for {
			if _, err := io.Copy(logger, r); err == nil {
				break
			}
		}
		wg.Done()
	}()
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// 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 (
	"database/sql"
	"encoding/hex"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"regexp"

	"github.com/spf13/cobra"
	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/mails"
	"github.com/toomore/mailbox/reader"
	"github.com/toomore/mailbox/utils"
)

var (
	servercExpr      = regexp.MustCompile(`/(read|door|washi)/([0-9a-z]+)`)
	serverhttpPort   *string
	serverlinksCache = make(map[string]string)
	serverConn       *sql.DB
)

func serverLog(note string, r *http.Request) {
	log.Printf("%s [%s] \"%+v\" %s\n", note, r.Header.Get("X-Real-Ip"), r, r.Header.Get("User-Agent"))
}

func read(w http.ResponseWriter, r *http.Request) {
	v, _ := url.ParseQuery(r.Header.Get("X-Args"))

	var hm string
	match := servercExpr.FindStringSubmatch(r.Header.Get("X-Uri"))
	if len(match) >= 3 {
		hm = match[2]
	}
	w.WriteHeader(http.StatusNotFound)
	hmbyte, _ := hex.DecodeString(hm)
	if campaign.CheckMac(hmbyte, v.Get("c"), v) {
		serverLog("[read] Pass", r)
		reader.Save(v.Get("c"), v.Get("u"), r.Header.Get("X-Real-Ip"), r.Header.Get("User-Agent"))
	} else {
		serverLog("[read] Hash Fail!!!", r)
	}
}

func washi(v url.Values, url string) []byte {
	washigroup := regexp.MustCompile(`{{WASHI}}(.+){{/WASHI}}`).FindStringSubmatch(url)
	if len(washigroup) > 1 {
		washiURL := []byte(washigroup[1])
		userrows, err := serverConn.Query(`SELECT f_name, l_name from user WHERE id=?`, v.Get("u"))
		if err == nil {
			for userrows.Next() {
				var (
					fname string
					lname string
				)
				userrows.Scan(&fname, &lname)
				mails.ReplaceFname(&washiURL, fname)
				mails.ReplaceLname(&washiURL, lname)
				return washiURL
			}
		}
	}
	return nil
}

func door(w http.ResponseWriter, r *http.Request) {
	v, _ := url.ParseQuery(r.Header.Get("X-Args"))

	match := servercExpr.FindStringSubmatch(r.Header.Get("X-Uri"))
	if match[1] == "door" {
		if v.Get("t") != "a" {
			log.Println("No `t`", v.Get("t"))
			return
		}
	}

	var hm string
	if len(match) >= 3 {
		hm = match[2]
	}

	hmbyte, _ := hex.DecodeString(hm)
	if campaign.CheckMac(hmbyte, v.Get("c"), v) {
		serverConn.Query(`INSERT INTO doors(cid,uid,linkid,ip,agent) VALUES(?,?,?,?,?)`,
			v.Get("c"), v.Get("u"), v.Get("l"), r.Header.Get("X-Real-Ip"), r.Header.Get("User-Agent"))
		serverLog("[door] Pass", r)

		serverlinksCacheKey := fmt.Sprintf("%s|%s", v.Get("c"), v.Get("l"))
		if url, ok := serverlinksCache[serverlinksCacheKey]; ok {
			log.Println("Using", match[1], "cache", serverlinksCacheKey, url)
			switch match[1] {
			case "door":
				http.Redirect(w, r, url, http.StatusSeeOther)
				return
			case "washi":
				http.Redirect(w, r, string(washi(v, url)), http.StatusSeeOther)
				return
			}
		}

		rows, err := serverConn.Query(`SELECT url FROM links WHERE cid=? AND id=?`, v.Get("c"), v.Get("l"))
		if err == nil {
			for rows.Next() {
				var url string
				rows.Scan(&url)
				serverlinksCache[serverlinksCacheKey] = url
				log.Println("Find", match[1], serverlinksCacheKey, url)
				switch match[1] {
				case "door":
					http.Redirect(w, r, url, http.StatusSeeOther)
					return
				case "washi":
					http.Redirect(w, r, string(washi(v, url)), http.StatusSeeOther)
					return
				}
			}
		}
	} else {
		serverLog("[door] Hash Fail!!!", r)
	}
	w.WriteHeader(http.StatusNotFound)
}

// serverCmd represents the server command
var serverCmd = &cobra.Command{
	Use:   "server",
	Short: "Run tiny server for open, click trace",
	Long:  `啟動一個 web server，來接收開信、點擊連結紀錄。`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		serverConn = utils.GetConn()
	},
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Run server ...")
		http.HandleFunc("/read/", read)
		http.HandleFunc("/door/", door)
		http.HandleFunc("/washi/", door)
		log.Println("HTTP Port:", *serverhttpPort)
		log.Println(http.ListenAndServe(*serverhttpPort, nil))
	},
}

func init() {
	serverhttpPort = serverCmd.Flags().StringP("port", "p", ":8801", "HTTP Port")
	RootCmd.AddCommand(serverCmd)

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

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

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// serverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
<commit_msg>Better<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// 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 (
	"database/sql"
	"encoding/hex"
	"fmt"
	"log"
	"net/http"
	"net/url"
	"regexp"

	"github.com/spf13/cobra"
	"github.com/toomore/mailbox/campaign"
	"github.com/toomore/mailbox/mails"
	"github.com/toomore/mailbox/reader"
	"github.com/toomore/mailbox/utils"
)

var (
	servercExpr      = regexp.MustCompile(`/(read|door|washi)/([0-9a-z]+)`)
	serverhttpPort   *string
	serverlinksCache = make(map[string]string)
	serverConn       *sql.DB
)

func serverLog(note string, r *http.Request) {
	log.Printf("%s [%s] \"%+v\" %s\n", note, r.Header.Get("X-Real-Ip"), r, r.Header.Get("User-Agent"))
}

func read(w http.ResponseWriter, r *http.Request) {
	v, _ := url.ParseQuery(r.Header.Get("X-Args"))

	var hm string
	match := servercExpr.FindStringSubmatch(r.Header.Get("X-Uri"))
	if len(match) >= 3 {
		hm = match[2]
	}
	w.WriteHeader(http.StatusNotFound)
	hmbyte, _ := hex.DecodeString(hm)
	if campaign.CheckMac(hmbyte, v.Get("c"), v) {
		serverLog("[read] Pass", r)
		reader.Save(v.Get("c"), v.Get("u"), r.Header.Get("X-Real-Ip"), r.Header.Get("User-Agent"))
	} else {
		serverLog("[read] Hash Fail!!!", r)
	}
}

func washi(v url.Values, url string) []byte {
	washigroup := regexp.MustCompile(`{{WASHI}}(.+){{/WASHI}}`).FindStringSubmatch(url)
	if len(washigroup) > 1 {
		userrows, err := serverConn.Query(`SELECT f_name, l_name from user WHERE id=?`, v.Get("u"))
		if err == nil {
			washiURL := []byte(washigroup[1])
			for userrows.Next() {
				var (
					fname string
					lname string
				)
				userrows.Scan(&fname, &lname)
				mails.ReplaceFname(&washiURL, fname)
				mails.ReplaceLname(&washiURL, lname)
				return washiURL
			}
		}
	}
	return nil
}

func door(w http.ResponseWriter, r *http.Request) {
	v, _ := url.ParseQuery(r.Header.Get("X-Args"))

	match := servercExpr.FindStringSubmatch(r.Header.Get("X-Uri"))
	if match[1] == "door" {
		if v.Get("t") != "a" {
			log.Println("No `t`", v.Get("t"))
			return
		}
	}

	var hm string
	if len(match) >= 3 {
		hm = match[2]
	}

	hmbyte, _ := hex.DecodeString(hm)
	if campaign.CheckMac(hmbyte, v.Get("c"), v) {
		serverConn.Query(`INSERT INTO doors(cid,uid,linkid,ip,agent) VALUES(?,?,?,?,?)`,
			v.Get("c"), v.Get("u"), v.Get("l"), r.Header.Get("X-Real-Ip"), r.Header.Get("User-Agent"))
		serverLog("[door] Pass", r)

		serverlinksCacheKey := fmt.Sprintf("%s|%s", v.Get("c"), v.Get("l"))
		if url, ok := serverlinksCache[serverlinksCacheKey]; ok {
			log.Println("Using", match[1], "cache", serverlinksCacheKey, url)
			switch match[1] {
			case "door":
				http.Redirect(w, r, url, http.StatusSeeOther)
				return
			case "washi":
				http.Redirect(w, r, string(washi(v, url)), http.StatusSeeOther)
				return
			}
		}

		rows, err := serverConn.Query(`SELECT url FROM links WHERE cid=? AND id=?`, v.Get("c"), v.Get("l"))
		if err == nil {
			for rows.Next() {
				var url string
				rows.Scan(&url)
				serverlinksCache[serverlinksCacheKey] = url
				log.Println("Find", match[1], serverlinksCacheKey, url)
				switch match[1] {
				case "door":
					http.Redirect(w, r, url, http.StatusSeeOther)
					return
				case "washi":
					http.Redirect(w, r, string(washi(v, url)), http.StatusSeeOther)
					return
				}
			}
		}
	} else {
		serverLog("[door] Hash Fail!!!", r)
	}
	w.WriteHeader(http.StatusNotFound)
}

// serverCmd represents the server command
var serverCmd = &cobra.Command{
	Use:   "server",
	Short: "Run tiny server for open, click trace",
	Long:  `啟動一個 web server，來接收開信、點擊連結紀錄。`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		serverConn = utils.GetConn()
	},
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Run server ...")
		http.HandleFunc("/read/", read)
		http.HandleFunc("/door/", door)
		http.HandleFunc("/washi/", door)
		log.Println("HTTP Port:", *serverhttpPort)
		log.Println(http.ListenAndServe(*serverhttpPort, nil))
	},
}

func init() {
	serverhttpPort = serverCmd.Flags().StringP("port", "p", ":8801", "HTTP Port")
	RootCmd.AddCommand(serverCmd)

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

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

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


<commit_before>// Copyright © 2016 Transparencia Mexicana AC. <ben@datos.mx>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"

	"github.com/bcessa/tsv/data"
	"github.com/bcessa/tsv/notifications"
	"github.com/bcessa/tsv/storage"
	"github.com/gorilla/websocket"
	"github.com/julienschmidt/httprouter"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// serverCmd represents the serve command
var serverCmd = &cobra.Command{
	Use:     "server",
	Short:   "Starts a TSV server instance",
	Aliases: []string{"serve"},
	RunE:    runServer,
}

// WebSocket factory, adjust an incoming HTTP connection to include WS support
var wsu = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// Setup
func init() {
	var (
		serverPort  int
		serverDocs  string
		serverStore string
	)
	viper.SetDefault("server.port", 7788)
	viper.SetDefault("server.docs", "htdocs")
	viper.SetDefault("server.store", os.TempDir())
	serverCmd.Flags().IntVarP(
		&serverPort,
		"port",
		"p",
		7788,
		"TCP port to use for server/client communications")
	serverCmd.Flags().StringVarP(
		&serverDocs,
		"htdocs",
		"c",
		"htdocs",
		"Full path for the content to serve")
	serverCmd.Flags().StringVarP(
		&serverStore,
		"store",
		"s",
		os.TempDir(),
		"Full path to use as data store location")
	viper.BindPFlag("server.port", serverCmd.Flags().Lookup("port"))
	viper.BindPFlag("server.docs", serverCmd.Flags().Lookup("htdocs"))
	viper.BindPFlag("server.store", serverCmd.Flags().Lookup("store"))
	RootCmd.AddCommand(serverCmd)
}

// Create or update a user profile
func profile(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// Open storage
	store, err := data.OpenStorage()
	if err != nil {
		log.Println("Storage error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	defer store.Close()

	up := data.UserProfile{}
	err = json.Unmarshal([]byte(r.FormValue("profile")), &up)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	log.Printf("Store user profile: %s\n", up.User)
	store.Write("profile", []byte(up.User), []byte(r.FormValue("profile")))

	// Dispatch SMS notification
	if up.EnableSMSNotifications {
		smsID, err := notifications.SendSMS(&notifications.SMSOptions{
			To:      fmt.Sprintf("+52%s", up.NotificationSMS),
			Sender:  "TS2",
			Message: "Bienvenido a Testigo Social Virtual 2.0 a partir de este momento comenzaras a recibir notificaciones relevantes",
		})
		if err != nil {
			log.Println("SMS error:", err)
		}
		log.Println("SMS notifications dipatched with ID:", smsID)
	}

	// Dispatch email notification
	if up.EnableEmailNotifications {
		content, _ := notifications.PrepareContent(notifications.TSVEmailTemplate, map[string]interface{}{
			"Title":   "¡Gracias por tu interés!",
			"Content": "Bienvenido a Testigo Social Virtual 2.0 a partir de este momento comenzaras a recibir notificaciones relevantes sobre los procesos de contratación pública de tu interes.",
		})
		emailID, err := notifications.SendEmail(&notifications.EmailOptions{
			To:      up.NotificationEmail,
			From:    "notificaciones@testigosocial.mx",
			Subject: "TS 2.0",
			Body:    content,
		})
		if err != nil {
			log.Println("Email error:", err)
		}
		log.Println("Email notifications dipatched with ID:", emailID)
	}

	fmt.Fprintf(w, fmt.Sprintf("{\"ok\":true}"))
}

// Calculate and return stats about the contracts on a specific storage bucket
func stats(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	// Open storage
	store, err := data.OpenStorage()
	if err != nil {
		log.Println("Storage error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	defer store.Close()

	log.Printf("Calculating stats for: %s\n", ps.ByName("bucket"))
	org := data.NewOrganization()
	org.Code = ps.ByName("bucket")
	switch org.Code {
	case "gacm":
		org.Description = "Nuevo Aeropuerto Internacional de la Ciudad de México"
	case "cdmx":
		org.Description = "Contratación de Servicios y Obras de la Ciudad de México"
	}

	cursor := make(chan *storage.Record)
	go store.Cursor(ps.ByName("bucket"), cursor, nil)
	for rec := range cursor {
		org.AddRecord(rec.Value)
	}

	res, _ := json.Marshal(org)
	fmt.Fprintf(w, string(res))
}

// Contracts list query
func query(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	query := data.Query{}
	err := json.Unmarshal([]byte(r.FormValue("query")), &query)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	query.Bucket = ps.ByName("bucket")

	log.Printf("Running query: %+v\n", query)
	res, _ := json.Marshal(query.Run())
	fmt.Fprintf(w, fmt.Sprintf("%s", res))
}

// Statistics query
func indicators(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	query := data.IndicatorsQuery{}
	err := json.Unmarshal([]byte(r.FormValue("query")), &query)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}

	log.Printf("Running indicators query: %+v\n", query)
	res, _ := json.Marshal(query.Run())
	fmt.Fprintf(w, fmt.Sprintf("%s", res))
}

// Store pre-register email
func preregister(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	log.Printf("Pre-register for: %+v\n", r.FormValue("email"))
	f, err := os.OpenFile("/data/pre-register", os.O_APPEND|os.O_WRONLY, 0600)
	if err == nil {
		f.WriteString(fmt.Sprintf("%s\n", r.FormValue("email")))
	}
	defer f.Close()
	fmt.Fprintf(w, fmt.Sprintf("%s", "ok"))
}

// Handle websockets
func ws(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	c, err := wsu.Upgrade(w, r, nil)
	if err != nil {
		log.Println("ws:", err)
		return
	}

	go func(c *websocket.Conn) {
		for {
			mType, data, err := c.ReadMessage()
			if err != nil {
				// Close connection upon request or error
				c.Close()
				return
			}

			// TODO - Handle messages
			log.Printf("message: %+v - %+v", mType, data)
			c.WriteMessage(mType, data)
		}
	}(c)
}

func runServer(cmd *cobra.Command, args []string) error {
	// Set storage config variable
	os.Setenv("TSV_STORAGE", path.Join(viper.GetString("server.store"), "tsv.db"))

	// Subscribe to SIGINT signals
	stopChan := make(chan os.Signal)
	signal.Notify(stopChan, os.Interrupt)

	// Configure router
	router := httprouter.New()
	router.NotFound = http.FileServer(http.Dir(viper.GetString("server.docs")))
	router.POST("/profile", profile)
	router.POST("/query/:bucket", query)
	router.POST("/indicators", indicators)
	router.POST("/preregister", preregister)
	router.GET("/stats/:bucket", stats)
	router.GET("/ws", ws)

	// Start server
	log.Println("Handling requests on port:", viper.GetInt("server.port"))
	go func() {
		addr := fmt.Sprintf(":%d", viper.GetInt("server.port"))
		if err := http.ListenAndServe(addr, router); err != nil {
			log.Printf("Connection error: %s\n", err)
		}
	}()

	// Wait for SIGINT
	<-stopChan
	log.Println("Shutting down server")
	return nil
}
<commit_msg>HTTPS<commit_after>// Copyright © 2016 Transparencia Mexicana AC. <ben@datos.mx>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path"

	"github.com/bcessa/tsv/data"
	"github.com/bcessa/tsv/notifications"
	"github.com/bcessa/tsv/storage"
	"github.com/gorilla/websocket"
	"github.com/julienschmidt/httprouter"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// serverCmd represents the serve command
var serverCmd = &cobra.Command{
	Use:     "server",
	Short:   "Starts a TSV server instance",
	Aliases: []string{"serve"},
	RunE:    runServer,
}

// WebSocket factory, adjust an incoming HTTP connection to include WS support
var wsu = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// Setup
func init() {
	var (
		serverPort    int
		serverDocs    string
		serverStore   string
		serverSSLCert string
		serverSSLKey  string
	)
	viper.SetDefault("server.port", 7788)
	viper.SetDefault("server.docs", "htdocs")
	viper.SetDefault("server.store", os.TempDir())
	serverCmd.Flags().IntVarP(
		&serverPort,
		"port",
		"p",
		7788,
		"TCP port to use for server/client communications")
	serverCmd.Flags().StringVarP(
		&serverDocs,
		"htdocs",
		"c",
		"htdocs",
		"Full path for the content to serve")
	serverCmd.Flags().StringVarP(
		&serverStore,
		"store",
		"s",
		os.TempDir(),
		"Full path to use as data store location")
	serverCmd.Flags().StringVar(
		&serverSSLCert,
		"cert",
		"",
		"SSL certificate to enable HTTPS")
	serverCmd.Flags().StringVar(
		&serverSSLKey,
		"priv-key",
		"",
		"SSL certificate's private key")
	viper.BindPFlag("server.port", serverCmd.Flags().Lookup("port"))
	viper.BindPFlag("server.docs", serverCmd.Flags().Lookup("htdocs"))
	viper.BindPFlag("server.store", serverCmd.Flags().Lookup("store"))
	viper.BindPFlag("server.cert", serverCmd.Flags().Lookup("cert"))
	viper.BindPFlag("server.priv", serverCmd.Flags().Lookup("priv-key"))
	RootCmd.AddCommand(serverCmd)
}

// Create or update a user profile
func profile(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	// Open storage
	store, err := data.OpenStorage()
	if err != nil {
		log.Println("Storage error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	defer store.Close()

	up := data.UserProfile{}
	err = json.Unmarshal([]byte(r.FormValue("profile")), &up)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	log.Printf("Store user profile: %s\n", up.User)
	store.Write("profile", []byte(up.User), []byte(r.FormValue("profile")))

	// Dispatch SMS notification
	if up.EnableSMSNotifications {
		smsID, err := notifications.SendSMS(&notifications.SMSOptions{
			To:      fmt.Sprintf("+52%s", up.NotificationSMS),
			Sender:  "TS2",
			Message: "Bienvenido a Testigo Social Virtual 2.0 a partir de este momento comenzaras a recibir notificaciones relevantes",
		})
		if err != nil {
			log.Println("SMS error:", err)
		}
		log.Println("SMS notifications dipatched with ID:", smsID)
	}

	// Dispatch email notification
	if up.EnableEmailNotifications {
		content, _ := notifications.PrepareContent(notifications.TSVEmailTemplate, map[string]interface{}{
			"Title":   "¡Gracias por tu interés!",
			"Content": "Bienvenido a Testigo Social Virtual 2.0 a partir de este momento comenzaras a recibir notificaciones relevantes sobre los procesos de contratación pública de tu interes.",
		})
		emailID, err := notifications.SendEmail(&notifications.EmailOptions{
			To:      up.NotificationEmail,
			From:    "notificaciones@testigosocial.mx",
			Subject: "TS 2.0",
			Body:    content,
		})
		if err != nil {
			log.Println("Email error:", err)
		}
		log.Println("Email notifications dipatched with ID:", emailID)
	}

	fmt.Fprintf(w, fmt.Sprintf("{\"ok\":true}"))
}

// Calculate and return stats about the contracts on a specific storage bucket
func stats(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	// Open storage
	store, err := data.OpenStorage()
	if err != nil {
		log.Println("Storage error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	defer store.Close()

	log.Printf("Calculating stats for: %s\n", ps.ByName("bucket"))
	org := data.NewOrganization()
	org.Code = ps.ByName("bucket")
	switch org.Code {
	case "gacm":
		org.Description = "Nuevo Aeropuerto Internacional de la Ciudad de México"
	case "cdmx":
		org.Description = "Contratación de Servicios y Obras de la Ciudad de México"
	}

	cursor := make(chan *storage.Record)
	go store.Cursor(ps.ByName("bucket"), cursor, nil)
	for rec := range cursor {
		org.AddRecord(rec.Value)
	}

	res, _ := json.Marshal(org)
	fmt.Fprintf(w, string(res))
}

// Contracts list query
func query(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	query := data.Query{}
	err := json.Unmarshal([]byte(r.FormValue("query")), &query)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}
	query.Bucket = ps.ByName("bucket")

	log.Printf("Running query: %+v\n", query)
	res, _ := json.Marshal(query.Run())
	fmt.Fprintf(w, fmt.Sprintf("%s", res))
}

// Statistics query
func indicators(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	query := data.IndicatorsQuery{}
	err := json.Unmarshal([]byte(r.FormValue("query")), &query)
	if err != nil {
		log.Println("Decoding error:", err)
		fmt.Fprintf(w, fmt.Sprintf("{\"error\":\"%s\"}", err.Error()))
		return
	}

	log.Printf("Running indicators query: %+v\n", query)
	res, _ := json.Marshal(query.Run())
	fmt.Fprintf(w, fmt.Sprintf("%s", res))
}

// Store pre-register email
func preregister(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	log.Printf("Pre-register for: %+v\n", r.FormValue("email"))
	f, err := os.OpenFile("/data/pre-register", os.O_APPEND|os.O_WRONLY, 0600)
	if err == nil {
		f.WriteString(fmt.Sprintf("%s\n", r.FormValue("email")))
	}
	defer f.Close()
	fmt.Fprintf(w, fmt.Sprintf("%s", "ok"))
}

// Handle websockets
func ws(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	c, err := wsu.Upgrade(w, r, nil)
	if err != nil {
		log.Println("ws:", err)
		return
	}

	go func(c *websocket.Conn) {
		for {
			mType, data, err := c.ReadMessage()
			if err != nil {
				// Close connection upon request or error
				c.Close()
				return
			}

			// TODO - Handle messages
			log.Printf("message: %+v - %+v", mType, data)
			c.WriteMessage(mType, data)
		}
	}(c)
}

func runServer(cmd *cobra.Command, args []string) error {
	// Set storage config variable
	os.Setenv("TSV_STORAGE", path.Join(viper.GetString("server.store"), "tsv.db"))

	// Subscribe to SIGINT signals
	stopChan := make(chan os.Signal)
	signal.Notify(stopChan, os.Interrupt)

	// Configure router
	router := httprouter.New()
	router.NotFound = http.FileServer(http.Dir(viper.GetString("server.docs")))
	router.POST("/profile", profile)
	router.POST("/query/:bucket", query)
	router.POST("/indicators", indicators)
	router.POST("/preregister", preregister)
	router.GET("/stats/:bucket", stats)
	router.GET("/ws", ws)

	// Start server
	log.Println("Handling requests on port:", viper.GetInt("server.port"))
	go func() {
		cert := viper.GetString("server.cert")
		priv := viper.GetString("server.priv")
		addr := fmt.Sprintf(":%d", viper.GetInt("server.port"))
		if cert != "" && priv != "" {
			// Secure HTTPS server
			if err := http.ListenAndServeTLS(addr, cert, priv, router); err != nil {
				log.Printf("HTTPS server error: %s\n", err)
			}
		} else {
			// Standard HTTP server
			if err := http.ListenAndServe(addr, router); err != nil {
				log.Printf("HTTP server error: %s\n", err)
			}
		}
	}()

	// Wait for SIGINT
	<-stopChan
	log.Println("Shutting down server")
	return nil
}
<|endoftext|>


<commit_before>package integration_test

import (
	"github.com/cloudfoundry/libbuildpack/cutlass"

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

var _ = Describe("deploy an app that shows the directory index", func() {
	var app *cutlass.App
	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil
	})

	BeforeEach(func() {
		app = cutlass.New(Fixtures("directory_index"))
	})

	It("runs", func() {
		PushAppAndConfirm(app)

		body, err := app.GetBody("/")
		Expect(err).To(BeNil())
		Expect(body).To(ContainSubstring("find-me-too.html"))
		Expect(body).To(ContainSubstring("find-me.html"))

		body, err = app.GetBody("/subdir")
		Expect(err).To(BeNil())
		Expect(body).To(ContainSubstring("This index file should still load normally when viewing a directory; and not a directory index."))
	})
})
<commit_msg>Fixes whitespace<commit_after>package integration_test

import (
	"github.com/cloudfoundry/libbuildpack/cutlass"

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

var _ = Describe("deploy an app that shows the directory index", func() {
	var app *cutlass.App

	AfterEach(func() {
		if app != nil {
			app.Destroy()
		}
		app = nil
	})

	BeforeEach(func() {
		app = cutlass.New(Fixtures("directory_index"))
	})

	It("runs", func() {
		PushAppAndConfirm(app)

		body, err := app.GetBody("/")
		Expect(err).To(BeNil())
		Expect(body).To(ContainSubstring("find-me-too.html"))
		Expect(body).To(ContainSubstring("find-me.html"))

		body, err = app.GetBody("/subdir")
		Expect(err).To(BeNil())
		Expect(body).To(ContainSubstring("This index file should still load normally when viewing a directory; and not a directory index."))
	})
})
<|endoftext|>


<commit_before>package hardware

import (
	"fmt"
	"plugin"
	"reflect"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/robertsdionne/dcpu"
)

type device struct {
	execute                 func(*dcpu.DCPU)
	getID                   func() uint32
	getManufacturerID       func() uint32
	getVersion              func() uint16
	handleHardwareInterrupt func(*dcpu.DCPU)
}

func (d *device) Execute(dcpu *dcpu.DCPU) {
	d.execute(dcpu)
}

func (d *device) GetID() uint32 {
	return d.getID()
}

func (d *device) GetManufacturerID() uint32 {
	return d.getManufacturerID()
}

func (d *device) GetVersion() uint16 {
	return d.getVersion()
}

func (d *device) HandleHardwareInterrupt(dcpu *dcpu.DCPU) {
	d.handleHardwareInterrupt(dcpu)
}

func OpenPlugin(path string) (hardware dcpu.Hardware, err error) {
	p, err := plugin.Open(path)
	if err != nil {
		return
	}

	var errs *multierror.Error

	execute, err := p.Lookup("Execute")
	errs = multierror.Append(errs, err)

	getID, err := p.Lookup("GetID")
	errs = multierror.Append(errs, err)

	getManufacturerID, err := p.Lookup("GetManufacturerID")
	errs = multierror.Append(errs, err)

	getVersion, err := p.Lookup("GetVersion")
	errs = multierror.Append(errs, err)

	handleHardwareInterrupt, err := p.Lookup("HandleHardwareInterrupt")
	errs = multierror.Append(errs, err)

	d := &device{}

	if execute, ok := execute.(func(*dcpu.DCPU)); ok {
		d.execute = execute
	} else {
		errs = multierror.Append(errs, fmt.Errorf(
			"Execute had invalid type: expected %s, got %s", reflect.TypeOf(d.execute), reflect.TypeOf(execute)))
	}

	if getID, ok := getID.(func() uint32); ok {
		d.getID = getID
	} else {
		errs = multierror.Append(
			errs, fmt.Errorf("GetID had invalid type: expected %s, got %s", reflect.TypeOf(d.getID), reflect.TypeOf(execute)))
	}

	if getManufacturerID, ok := getManufacturerID.(func() uint32); ok {
		d.getManufacturerID = getManufacturerID
	} else {
		errs = multierror.Append(errs, fmt.Errorf("GetManufacturerID had invalid type: expected %s, got %s",
			reflect.TypeOf(d.getManufacturerID), reflect.TypeOf(getManufacturerID)))
	}

	if getVersion, ok := getVersion.(func() uint16); ok {
		d.getVersion = getVersion
	} else {
		errs = multierror.Append(errs, fmt.Errorf(
			"GetVersion had invalid type: expected %s, got %s", reflect.TypeOf(d.getVersion), reflect.TypeOf(getVersion)))
	}

	if handleHardwareInterrupt, ok := handleHardwareInterrupt.(func(*dcpu.DCPU)); ok {
		d.handleHardwareInterrupt = handleHardwareInterrupt
	} else {
		errs = multierror.Append(errs, fmt.Errorf("HandleHardwareInterrupt had invalid type: expected %s, got %s",
			reflect.TypeOf(d.handleHardwareInterrupt), reflect.TypeOf(handleHardwareInterrupt)))
	}

	hardware = d
	err = errs.ErrorOrNil()
	return
}
<commit_msg>Clean up error strings.<commit_after>package hardware

import (
	"fmt"
	"plugin"
	"reflect"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/robertsdionne/dcpu"
)

type device struct {
	execute                 func(*dcpu.DCPU)
	getID                   func() uint32
	getManufacturerID       func() uint32
	getVersion              func() uint16
	handleHardwareInterrupt func(*dcpu.DCPU)
}

func (d *device) Execute(dcpu *dcpu.DCPU) {
	d.execute(dcpu)
}

func (d *device) GetID() uint32 {
	return d.getID()
}

func (d *device) GetManufacturerID() uint32 {
	return d.getManufacturerID()
}

func (d *device) GetVersion() uint16 {
	return d.getVersion()
}

func (d *device) HandleHardwareInterrupt(dcpu *dcpu.DCPU) {
	d.handleHardwareInterrupt(dcpu)
}

const (
	errFormat = "%s had invalid type: expected %s, got %s"
)

func OpenPlugin(path string) (hardware dcpu.Hardware, err error) {
	p, err := plugin.Open(path)
	if err != nil {
		return
	}

	var errs *multierror.Error

	execute, err := p.Lookup("Execute")
	errs = multierror.Append(errs, err)

	getID, err := p.Lookup("GetID")
	errs = multierror.Append(errs, err)

	getManufacturerID, err := p.Lookup("GetManufacturerID")
	errs = multierror.Append(errs, err)

	getVersion, err := p.Lookup("GetVersion")
	errs = multierror.Append(errs, err)

	handleHardwareInterrupt, err := p.Lookup("HandleHardwareInterrupt")
	errs = multierror.Append(errs, err)

	d := &device{}

	if execute, ok := execute.(func(*dcpu.DCPU)); ok {
		d.execute = execute
	} else {
		errs = multierror.Append(errs, fmt.Errorf(errFormat, "Execute", reflect.TypeOf(d.execute), reflect.TypeOf(execute)))
	}

	if getID, ok := getID.(func() uint32); ok {
		d.getID = getID
	} else {
		errs = multierror.Append(errs, fmt.Errorf(errFormat, "GetID", reflect.TypeOf(d.getID), reflect.TypeOf(execute)))
	}

	if getManufacturerID, ok := getManufacturerID.(func() uint32); ok {
		d.getManufacturerID = getManufacturerID
	} else {
		errs = multierror.Append(errs, fmt.Errorf(errFormat,
			"GetManufacturerID", reflect.TypeOf(d.getManufacturerID), reflect.TypeOf(getManufacturerID)))
	}

	if getVersion, ok := getVersion.(func() uint16); ok {
		d.getVersion = getVersion
	} else {
		errs = multierror.Append(errs, fmt.Errorf(
			errFormat, "GetVersion", reflect.TypeOf(d.getVersion), reflect.TypeOf(getVersion)))
	}

	if handleHardwareInterrupt, ok := handleHardwareInterrupt.(func(*dcpu.DCPU)); ok {
		d.handleHardwareInterrupt = handleHardwareInterrupt
	} else {
		errs = multierror.Append(errs, fmt.Errorf(errFormat,
			"HandleHardwareInterrupt", reflect.TypeOf(d.handleHardwareInterrupt), reflect.TypeOf(handleHardwareInterrupt)))
	}

	hardware = d
	err = errs.ErrorOrNil()
	return
}
<|endoftext|>


<commit_before>package codegen

import (
	"log"
	"strings"

	"github.com/jkomoros/boardgame"
)

//allValidTypes is an enumeration of all types in order.
var allValidTypes []propertyType

//highestProperty is the highest enum in the PropertyType enum.
const highestProperty = boardgame.TypeTimer

func init() {
	//Only need space for highestProperty because we skip TypeIllegal.
	allValidTypes = make([]propertyType, highestProperty)
	//We skip TypeIllegal
	for i := 0; i < int(highestProperty); i++ {
		allValidTypes[i] = propertyType{boardgame.PropertyType(i + 1)}
	}
}

//propertyType is a simple wrapper around boardgame.PropertyType that extends it
//with methods that are only useful for codegen and thus don't belong in the
//main package. We can't just alias the type in this package because we need the
//methods. Note one oddity, to compare what type it is, you have to compare
//t.PropertyType == boardgame.TypeInt. Luckily the typechecker will complain if
//you do it wrong.
type propertyType struct {
	boardgame.PropertyType
}

//TypePackagePrefix returns a string representing the package prefix of the go
//type that is represented by this property type. For example, "boardgame." for
//TypeStack, and "" for TypeInt. Using strings.TrimPrefix() with this prefix
//applied to the return value of for example ImmutableGoType and others will
//strip away the package qualifier, if it exists. Most useful for the codegen
//package.
func (t propertyType) TypePackagePrefix() string {
	//Strip away any slices so we have fewer conditions to test for
	base := t.BaseType()
	switch base {
	case boardgame.TypePlayerIndex, boardgame.TypeStack, boardgame.TypeBoard, boardgame.TypeTimer:
		return "boardgame."
	case boardgame.TypeEnum:
		return "enum."
	}
	return ""
}

//ImmutableGoType emits strings like 'bool', 'boardgame.PlayerIndex'. It
//represents the type of this property for the immutable/getter contexts. Most
//useful for codegen package.
func (t propertyType) ImmutableGoType() string {

	if t.IsSlice() {
		return "[]" + propertyType{t.BaseType()}.ImmutableGoType()
	}

	switch t.PropertyType {
	case boardgame.TypeBool:
		return "bool"
	case boardgame.TypeInt:
		return "int"
	case boardgame.TypeString:
		return "string"
	case boardgame.TypePlayerIndex:
		return "boardgame.PlayerIndex"
	case boardgame.TypeEnum:
		return "enum.ImmutableVal"
	case boardgame.TypeStack:
		return "boardgame.ImmutableStack"
	case boardgame.TypeBoard:
		return "boardgame.ImmutableBoard"
	case boardgame.TypeTimer:
		return "boardgame.ImmutableTimer"
	default:
		return ""
	}
}

//MutableGoType emits a string representing the golang type for the property
//when in mutable/setter contexts, e.g 'int', 'boardgame.Stack'. Most useful for
//the codegen package.
func (t propertyType) MutableGoType() string {
	return strings.Replace(t.ImmutableGoType(), "Immutable", "", -1)
}

//Key returns the part of the PropertyReader method signature for this type. For
//example, "Bool" for TypeBool, "Timer" for "TypeTimer". Most useful for the
//codegen package.
func (t propertyType) Key() string {
	return strings.TrimPrefix(t.String(), "Type")
}

//ZeroValue returns the string representing the zeroValue for this type, e.g.
//"0" for TypeInt and "[]boardgame.PlayerIndex{}" for TypePlayerIndexSlice. Most
//useful for codgen package.
func (t propertyType) ZeroValue() string {

	switch t.PropertyType {
	case boardgame.TypeBool:
		return "false"
	case boardgame.TypeInt:
		return "0"
	case boardgame.TypeString:
		return "\"\""
	case boardgame.TypePlayerIndex:
		return "0"
	case boardgame.TypeIllegal:
		return ""
	}

	if t.IsSlice() {
		return t.ImmutableGoType() + "{}"
	}
	if t.IsInterface() {
		return "nil"
	}

	log.Println("Unexpected type for ZeroValue")
	return ""

}
<commit_msg>Add information to property types about the sub-type converters and anmes. Part of #746.<commit_after>package codegen

import (
	"log"
	"strings"

	"github.com/jkomoros/boardgame"
)

//allValidTypes is an enumeration of all types in order.
var allValidTypes []propertyType

//highestProperty is the highest enum in the PropertyType enum.
const highestProperty = boardgame.TypeTimer

func init() {
	//Only need space for highestProperty because we skip TypeIllegal.
	allValidTypes = make([]propertyType, highestProperty)
	//We skip TypeIllegal
	for i := 0; i < int(highestProperty); i++ {
		allValidTypes[i] = propertyType{boardgame.PropertyType(i + 1)}
	}
}

//propertyType is a simple wrapper around boardgame.PropertyType that extends it
//with methods that are only useful for codegen and thus don't belong in the
//main package. We can't just alias the type in this package because we need the
//methods. Note one oddity, to compare what type it is, you have to compare
//t.PropertyType == boardgame.TypeInt. Luckily the typechecker will complain if
//you do it wrong.
type propertyType struct {
	boardgame.PropertyType
}

//TypePackagePrefix returns a string representing the package prefix of the go
//type that is represented by this property type. For example, "boardgame." for
//TypeStack, and "" for TypeInt. Using strings.TrimPrefix() with this prefix
//applied to the return value of for example ImmutableGoType and others will
//strip away the package qualifier, if it exists. Most useful for the codegen
//package.
func (t propertyType) TypePackagePrefix() string {
	//Strip away any slices so we have fewer conditions to test for
	base := t.BaseType()
	switch base {
	case boardgame.TypePlayerIndex, boardgame.TypeStack, boardgame.TypeBoard, boardgame.TypeTimer:
		return "boardgame."
	case boardgame.TypeEnum:
		return "enum."
	}
	return ""
}

//ImmutableGoType emits strings like 'bool', 'boardgame.PlayerIndex'. It
//represents the type of this property for the immutable/getter contexts. Most
//useful for codegen package.
func (t propertyType) ImmutableGoType() string {

	if t.IsSlice() {
		return "[]" + propertyType{t.BaseType()}.ImmutableGoType()
	}

	switch t.PropertyType {
	case boardgame.TypeBool:
		return "bool"
	case boardgame.TypeInt:
		return "int"
	case boardgame.TypeString:
		return "string"
	case boardgame.TypePlayerIndex:
		return "boardgame.PlayerIndex"
	case boardgame.TypeEnum:
		return "enum.ImmutableVal"
	case boardgame.TypeStack:
		return "boardgame.ImmutableStack"
	case boardgame.TypeBoard:
		return "boardgame.ImmutableBoard"
	case boardgame.TypeTimer:
		return "boardgame.ImmutableTimer"
	default:
		return ""
	}
}

//MutableGoType emits a string representing the golang type for the property
//when in mutable/setter contexts, e.g 'int', 'boardgame.Stack'. Most useful for
//the codegen package.
func (t propertyType) MutableGoType() string {
	return strings.Replace(t.ImmutableGoType(), "Immutable", "", -1)
}

//Key returns the part of the PropertyReader method signature for this type. For
//example, "Bool" for TypeBool, "Timer" for "TypeTimer". Most useful for the
//codegen package.
func (t propertyType) Key() string {
	return strings.TrimPrefix(t.String(), "Type")
}

//ImmutableSubTypeConverters will return the names of hte converters to convert
//to the various valid subtypes, e.g. "ImmutableSizedStack" for TypeStack.
func (t propertyType) ImmutableSubTypeConverters() []string {
	switch t.PropertyType {
	case boardgame.TypeStack:
		return []string{"MergedStack", "ImmutableSizedStack"}
	case boardgame.TypeEnum:
		return []string{"ImmutableTreeVal", "ImmutableRangeVal"}
	}
	return nil
}

//MutableSubTypeConverters will return the names of hte converters to convert
//to the various valid subtypes, e.g. "ImmutableSizedStack" for TypeStack.
func (t propertyType) MutableSubTypeConverters() []string {
	switch t.PropertyType {
	case boardgame.TypeStack:
		return []string{"SizedStack"}
	case boardgame.TypeEnum:
		return []string{"TreeVal", "RangeVal"}
	}
	return nil
}

//ImmutableSubTypes returns the sub type fully qualitfied type strings for
//sub-types, e.g. "enum.ImmutableRangeVal" for boardgame.TypeEnum.
func (t propertyType) ImmutableSubTypes() []string {
	//Since the convertesr by convention are literally just the name of the type
	//(minus the package qualifier) we can just strip the package name.
	prefix := t.TypePackagePrefix()
	var result []string
	for _, item := range t.ImmutableSubTypeConverters() {
		result = append(result, strings.TrimPrefix(item, prefix))
	}
	return result
}

//MutableSubTypes returns the sub type fully qualitfied type strings for
//sub-types, e.g. "enum.ImmutableRangeVal" for boardgame.TypeEnum.
func (t propertyType) MutableSubTypes() []string {
	//Since the convertesr by convention are literally just the name of the type
	//(minus the package qualifier) we can just strip the package name.
	prefix := t.TypePackagePrefix()
	var result []string
	for _, item := range t.MutableSubTypeConverters() {
		result = append(result, strings.TrimPrefix(item, prefix))
	}
	return result
}

//ZeroValue returns the string representing the zeroValue for this type, e.g.
//"0" for TypeInt and "[]boardgame.PlayerIndex{}" for TypePlayerIndexSlice. Most
//useful for codgen package.
func (t propertyType) ZeroValue() string {

	switch t.PropertyType {
	case boardgame.TypeBool:
		return "false"
	case boardgame.TypeInt:
		return "0"
	case boardgame.TypeString:
		return "\"\""
	case boardgame.TypePlayerIndex:
		return "0"
	case boardgame.TypeIllegal:
		return ""
	}

	if t.IsSlice() {
		return t.ImmutableGoType() + "{}"
	}
	if t.IsInterface() {
		return "nil"
	}

	log.Println("Unexpected type for ZeroValue")
	return ""

}
<|endoftext|>