func sliceFind(slice []string, val string) (int, bool) {
	for i, item := range slice {
		if item == val {
			return i, true
		}
	}
	return -1, false
}
sliceFind takes a slice and looks for an element in it. If found it will
return it's key, otherwise it will return -1 and a bool of false.
package main
import (
	"bufio"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
)
var (
	kubeEnv = ""
	version = "devel"
)
func init() {
	log.SetFlags(0)
	_, err := exec.LookPath("kubectl")
	if err != nil {
		log.Fatalln(err)
	}
}
func main() {
	if len(os.Args) == 1 {
		usage()
		os.Exit(0)
	}
	_, kDebugBool := os.LookupEnv("K_DEBUG")
	var passedArgs []string
	for _, arg := range os.Args[1:] {
		passedArgs = append(passedArgs, arg)
	}
	namespace, envSet := os.LookupEnv("KUBE_NAMESPACE")
	if envSet {
		_, foundNS := sliceFind(passedArgs, "--namespace")
		_, foundNS2 := sliceFind(passedArgs, "-n")
		if !foundNS && !foundNS2 {
			passedArgs = append(passedArgs, "--namespace", namespace)
		}
	}
	context, envSet := os.LookupEnv("KUBE_CONTEXT")
	if envSet {
		_, foundContext := sliceFind(passedArgs, "--context")
		if !foundContext {
			passedArgs = append(passedArgs, "--context", context)
		}
	}
	_, kubeconfigEnvBool := os.LookupEnv("KUBECONFIG")
	_, kubeconfigArgBool := sliceFind(passedArgs, "--kubeconfig")
	if !kubeconfigEnvBool && !kubeconfigArgBool {
		kubeEnv = buildKubeconfig()
	} else {
		kubeEnv = os.Getenv("KUBECONFIG")
	}
	if kDebugBool {
		fmt.Printf("[DEBUG] Arguments passed: %s\n", passedArgs)
		fmt.Printf("[DEBUG] Using KUBECONFIG: %s\n", kubeEnv)
	}
	kspacePrefixes := []string{"@", "+", ":"}
	var kspaces []string
	var args []string
	for _, arg := range passedArgs {
		if hasPrefixAny(arg, kspacePrefixes) {
			kspaces = append(kspaces, arg)
		} else {
			args = append(args, arg)
		}
	}
	if len(kspaces) > 0 {
		clustersMap, kSpaceNames := ParseCluster(kspaces)
		if len(clustersMap) > 1 {
			for name, cluster := range clustersMap {
				if kDebugBool {
					fmt.Println("[DEBUG] Detected multiple args")
				}
				if cluster.context != "" {
					args = append(args, "--context", cluster.context)
				} else {
					fmt.Fprintf(os.Stderr, "failed to process %+v\n", cluster)
					break
				}
				if cluster.namespace != "" {
					if cluster.namespace == "*" {
						args = append(args, "--all-namespaces")
					} else {
						args = append(args, "--namespace", cluster.namespace)
					}
				}
				if kDebugBool {
					fmt.Printf("[DEBUG] Running: kubectl %s\n", strings.Join(args, " "))
				}
				runKubectl(args, name)
			}
		} else if len(clustersMap) == 1 {
			cluster := clustersMap[kSpaceNames[0]]
			args := passedArgs[1:]
			if cluster.context != "" {
				args = append(args, "--context", cluster.context)
			} else {
				fmt.Fprintf(os.Stderr, "Failed to process %+v\n", cluster)
				os.Exit(1)
			}
			if cluster.namespace != "" {
				if cluster.namespace == "*" {
					args = append(args, "--all-namespaces")
				} else {
					args = append(args, "--namespace", cluster.namespace)
				}
			}
			if kDebugBool {
				fmt.Printf("[DEBUG] Running: kubectl %s\n", strings.Join(args, " "))
			}
			runKubectl(args, "")
		}
	} else {
		if kDebugBool {
			fmt.Printf("[DEBUG] Running: kubectl %s\n", strings.Join(passedArgs, " "))
		}
		runKubectl(passedArgs, "")
	}
}
func runKubectl(args []string, kspace string) {
	kCmd := exec.Command("kubectl", args...)
	kCmd.Env = nil
	kCmd.Env = append(os.Environ(),
		"KUBECONFIG="+kubeEnv,
	)
	fi, _ := os.Stdin.Stat()
	if (fi.Mode() & os.ModeCharDevice) == 0 {
		kCmd.Stdin = os.Stdin
	}
	stdout, err := kCmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	stderr, err := kCmd.StderrPipe()
	if err != nil {
		log.Fatal(err)
	}
	stdoutscanner := bufio.NewScanner(stdout)
	stderrscanner := bufio.NewScanner(stderr)
	doneChan := make(chan struct{})
	go func() {
		defer close(doneChan)
		for stdoutscanner.Scan() {
			line := stdoutscanner.Text()
			if kspace != "" {
				fmt.Printf("%s\t%s\n", kspace, line)
			} else {
				fmt.Println(line)
			}
		}
		for stderrscanner.Scan() {
			line := stderrscanner.Text()
			if kspace != "" {
				fmt.Printf("%s\t%s\n", kspace, line)
			} else {
				fmt.Println(line)
			}
		}
	}()
	err = kCmd.Run()
	if err != nil {
		if exitError, ok := err.(*exec.ExitError); ok {
			os.Exit(exitError.ExitCode())
		}
	}
}
func captureFirst(r *regexp.Regexp, s string) string {
	c := r.FindStringSubmatch(s)
	if len(c) > 1 {
		return c[1]
	}
	return ""
}
func ParseCluster(kspaces []string) (map[string]Cluster, []string) {
	kSpace := make(map[string]Cluster)
	var tmpCluster Cluster
	var tmpName string
	var maybeContext []string
	var maybeCluster []string
	var maybeNamespace []string
	for _, s := range kspaces {
		maybeContext = strings.Split(captureFirst(regexp.MustCompile(`(?:\+)([0-9A-Za-z_,.\-@]+)`), s), ",")  
		maybeCluster = strings.Split(captureFirst(regexp.MustCompile(`(?:@)([0-9A-Za-z_,.\-@]+)`), s), ",")   
		maybeNamespace = strings.Split(captureFirst(regexp.MustCompile(`(?::)(.+)(?:$)`), s), ",")            
		_, kDebugBool := os.LookupEnv("K_DEBUG")
		if kDebugBool {
			fmt.Println("[DEBUG] Parsed context(s): ", strings.Join(maybeContext, " "))
			fmt.Println("[DEBUG] Parsed namespace(s): ", strings.Join(maybeNamespace, " "))
			fmt.Println("[DEBUG] Parsed cluster(s): ", strings.Join(maybeCluster, " "))
		}
		if maybeContext[0] != "" {
			if len(maybeNamespace) > 0 && maybeNamespace[0] != "" {
				for _, ctx := range maybeContext {
					for _, ns := range maybeNamespace {
						tmpName = "+" + ctx + ":" + ns
						tmpCluster.context = ctx
						tmpCluster.namespace = ns
						kSpace[tmpName] = tmpCluster
					}
				}
			} else {
				for _, ctx := range maybeContext {
					tmpName = "+" + ctx
					tmpCluster.context = ctx
					kSpace[tmpName] = tmpCluster
				}
			}
		} else if maybeCluster[0] != "" {
			if len(maybeNamespace) > 0 && maybeNamespace[0] != "" {
				for _, cl := range maybeCluster {
					for _, ns := range maybeNamespace {
						tmpName = "@" + cl + ":" + ns
						tmpCluster.context = getContextFromCluster(cl)
						tmpCluster.cluster = cl
						tmpCluster.namespace = ns
						kSpace[tmpName] = tmpCluster
					}
				}
			} else {
				for _, cl := range maybeCluster {
					tmpName = "@" + cl
					tmpCluster.cluster = cl
					tmpCluster.context = getContextFromCluster(cl)
					kSpace[tmpName] = tmpCluster
				}
			}
		} else if maybeNamespace[0] != "" {
			for _, ns := range maybeNamespace {
				tmpName = ":" + ns
				tmpCluster.namespace = ns
				kSpace[tmpName] = tmpCluster
			}
		}
	}
	kNames := make([]string, len(kSpace))
	i := 0
	for k := range kSpace {
		kNames[i] = k
		i++
	}
	return kSpace, kNames
}
func getContextFromCluster(s string) string {
	var context string
	template := "{{ range .contexts  }}{{ printf \"%s %s\\n\" .name .context.cluster }}{{ end  }}"
	ctxCmd := exec.Command("kubectl", "config", "view", "--output", "template", "--template", template)
	ctxCmd.Env = append(os.Environ(),
		"KUBECONFIG="+kubeEnv,
	)
	ctxCmd.Stderr = os.Stderr
	ctxOutput, err := ctxCmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := ctxCmd.Start(); err != nil {
		log.Fatal(err)
	}
	_, kDebugBool := os.LookupEnv("K_DEBUG")
	scanner := bufio.NewScanner(ctxOutput)
	for scanner.Scan() {
		line := scanner.Text()
		if kDebugBool {
			fmt.Printf("[DEBUG] Looking for %s in %s\n", s, strings.Fields(line))
		}
		contextMatch, _ := regexp.MatchString(strings.Fields(line)[1], s)
		if contextMatch {
			context = strings.Fields(line)[0]
			if kDebugBool {
				fmt.Printf("[DEBUG] Found context: %s\n", context)
			}
			break
		}
	}
	if err := ctxCmd.Wait(); err != nil {
		log.Fatal(err)
	}
	return context
}
type Cluster struct {
	cluster   string
	namespace string
	context   string
}
func buildKubeconfig() (kc string) {
	var kubeconfig string
	err := filepath.Walk(os.Getenv("HOME")+"/.kube", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err)
			return err
		}
		if info.IsDir() && (info.Name() == "cache" || info.Name() == "http-cache") {
			return filepath.SkipDir
		}
		if !info.IsDir() {
			if len(kubeconfig) == 0 {
				kubeconfig = path
			} else {
				if path != "" {
					kubeconfig = kubeconfig + ":" + path
				}
			}
		}
		return nil
	})
	if err != nil {
		fmt.Printf("error walking the path")
		return
	}
	return strings.TrimSuffix(kubeconfig, ":")
}