From e00f78a4b1d5d96eedabb59deecc5a1e2ecc35b0 Mon Sep 17 00:00:00 2001 From: Zee Date: Sat, 14 Sep 2019 02:24:00 +0100 Subject: [PATCH] Adding support for cross compatability darwin / linux --- Makefile | 111 +++-------- cmd/install_darwin.go | 203 +++++++++++++++++++++ cmd/{install.go => install_linux.go} | 2 + cmd/listRemote_darwin.go | 92 ++++++++++ cmd/{listRemote.go => listRemote_linux.go} | 2 + cmd/list_darwin.go | 81 ++++++++ cmd/{list.go => list_linux.go} | 2 + cmd/remove_darwin.go | 74 ++++++++ cmd/{remove.go => remove_linux.go} | 2 + cmd/{root.go => root_darwin.go} | 2 + cmd/root_linux.go | 93 ++++++++++ cmd/use_darwin.go | 77 ++++++++ cmd/{use.go => use_linux.go} | 2 + cmd/version_darwin.go | 37 ++++ cmd/{version.go => version_linux.go} | 2 + 15 files changed, 699 insertions(+), 83 deletions(-) create mode 100644 cmd/install_darwin.go rename cmd/{install.go => install_linux.go} (99%) create mode 100644 cmd/listRemote_darwin.go rename cmd/{listRemote.go => listRemote_linux.go} (99%) create mode 100644 cmd/list_darwin.go rename cmd/{list.go => list_linux.go} (99%) create mode 100644 cmd/remove_darwin.go rename cmd/{remove.go => remove_linux.go} (99%) rename cmd/{root.go => root_darwin.go} (99%) create mode 100644 cmd/root_linux.go create mode 100644 cmd/use_darwin.go rename cmd/{use.go => use_linux.go} (99%) create mode 100644 cmd/version_darwin.go rename cmd/{version.go => version_linux.go} (98%) diff --git a/Makefile b/Makefile index 6502207..a2c6c84 100644 --- a/Makefile +++ b/Makefile @@ -1,95 +1,40 @@ --include .env +# ########################################################## # +# Makefile for Golang Project +# Includes cross-compiling, installation, cleanup +# ########################################################## # -VERSION := $(shell git describe --tags) -BUILD := $(shell git rev-parse --short HEAD) -PROJECTNAME := $(shell basename "$(PWD)") +# Check for required command tools to build or stop immediately +EXECUTABLES = git go find pwd +K := $(foreach exec,$(EXECUTABLES),\ + $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH))) -# Go related variables. -GOBASE := $(shell pwd) -GOPATH := $(GOBASE)/vendor:$(GOBASE) -GOBIN := $(GOBASE)/bin -GOFILES := $(wildcard *.go) +ROOT_DIR:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) -# Use linker flags to provide version/build settings -LDFLAGS=-ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD)" +BINARY=kubemngr +VERSION=0.0.1 +BUILD=`git rev-parse HEAD` +PLATFORMS=darwin linux #windows +ARCHITECTURES=386 amd64 -# Redirect error output to a file, so we can show it in development mode. -STDERR := /tmp/.$(PROJECTNAME)-stderr.txt +# Setup linker flags option for build that interoperate with variable names in src code +LDFLAGS=-ldflags "-X main.Version=${VERSION} -X main.Build=${BUILD}" -# PID file will keep the process id of the server -PID := /tmp/.$(PROJECTNAME).pid +default: build -# Make is verbose in Linux. Make it silent. -MAKEFLAGS += --silent +all: clean build_all install -## install: Install missing dependencies. Runs `go get` internally. e.g; make install get=github.com/foo/bar -install: go-get +build: + go build ${LDFLAGS} -o ${BINARY} -## start: Start in development mode. Auto-starts when code changes. -start: - @bash -c "trap 'make stop' EXIT; $(MAKE) clean compile start-server watch run='make clean compile start-server'" +build_all: + $(foreach GOOS, $(PLATFORMS),\ + $(foreach GOARCH, $(ARCHITECTURES), $(shell export GOOS=$(GOOS); export GOARCH=$(GOARCH); go build -v -o $(BINARY)-$(GOOS)-$(GOARCH)))) -## stop: Stop development mode. -stop: stop-server +install: + go install ${LDFLAGS} -start-server: stop-server - @echo " > $(PROJECTNAME) is available at $(ADDR)" - @-$(GOBIN)/$(PROJECTNAME) 2>&1 & echo $$! > $(PID) - @cat $(PID) | sed "/^/s/^/ \> PID: /" - -stop-server: - @-touch $(PID) - @-kill `cat $(PID)` 2> /dev/null || true - @-rm $(PID) - -## watch: Run given command when code changes. e.g; make watch run="echo 'hey'" -watch: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) yolo -i . -e vendor -e bin -c "$(run)" - -restart-server: stop-server start-server - -## compile: Compile the binary. -compile: - @-touch $(STDERR) - @-rm $(STDERR) - @-$(MAKE) -s go-compile 2> $(STDERR) - @cat $(STDERR) | sed -e '1s/.*/\nError:\n/' | sed 's/make\[.*/ /' | sed "/^/s/^/ /" 1>&2 - -## exec: Run given command, wrapped with custom GOPATH. e.g; make exec run="go test ./..." -exec: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) $(run) - -## clean: Clean build files. Runs `go clean` internally. +# Remove only what we've created clean: - @-rm $(GOBIN)/$(PROJECTNAME) 2> /dev/null - @-$(MAKE) go-clean - -go-compile: go-get go-build - -go-build: - @echo " > Building binary..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go build $(LDFLAGS) -o $(GOBIN)/$(PROJECTNAME) $(GOFILES) - -go-generate: - @echo " > Generating dependency files..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go generate $(generate) - -go-get: - @echo " > Checking if there is any missing dependencies..." - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go get $(get) - -go-install: - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go install $(GOFILES) - -go-clean: - @echo " > Cleaning build cache" - @GOPATH=$(GOPATH) GOBIN=$(GOBIN) go clean + find ${ROOT_DIR} -name '${BINARY}[-?][a-zA-Z0-9]*[-?][a-zA-Z0-9]*' -delete -.PHONY: help -all: help -help: Makefile - @echo - @echo " Choose a command run in "$(PROJECTNAME)":" - @echo - @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' - @echo \ No newline at end of file +.PHONY: check clean install build_all all diff --git a/cmd/install_darwin.go b/cmd/install_darwin.go new file mode 100644 index 0000000..02ca97b --- /dev/null +++ b/cmd/install_darwin.go @@ -0,0 +1,203 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + "io" + "log" + "net/http" + "os" + "strings" + "syscall" + + "github.com/dustin/go-humanize" + _ "github.com/google/go-github/v27/github" + "github.com/spf13/cobra" +) + +var sys, machine string + +type WriteCounter struct { + Total uint64 +} + +// installCmd represents the install command +var installCmd = &cobra.Command{ + Use: "install", + Short: "A tool manage different kubectl versions inside a workspace.", + //RunE: func(cmd *cobra.Command, args []string) error { + // return errors.New("provide a kubectl version") + //}, + Run: func(cmd *cobra.Command, args []string) { + err := DownloadKubectl(args[0]) + + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + rootCmd.AddCommand(installCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // installCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // installCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +//DownloadKubectl - download user specified version of kubectl +func DownloadKubectl(version string) error { + + // TODO use tmp directory to download instead of kubemngr. + // This was failing originally with the error: invalid cross-link device + // filepath := "/tmp/" + + // TODO better sanity check for checking arg is valid + if len(version) == 0 { + log.Fatal(0) + } + + // Get user home directory path + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal(err) + } + + // Check if current version already exists + _, err = os.Stat(homeDir + "/.kubemngr/kubectl-" + version) + if err == nil { + log.Printf("kubectl version %s already exists", version) + return nil + } + + // Create temp file of kubectl version in tmp directory + out, err := os.Create(homeDir + "/.kubemngr/kubectl-" + version + ".tmp") + if err != nil { + log.Fatal(err) + } + + defer out.Close() + + // Get OS information to filter download type i.e linux / darwin + uname := GetOSInfo() + + // TODO refactor me + // doesn't work on OSX + if ArrayToString(uname.Sysname) == "Linux" { + sys = "linux" + } else if ArrayToString(uname.Sysname) == "Darwin" { + sys = "darwin" + } else { + sys = "UNKNOWN" + fmt.Println("Unknown system") + } + + if ArrayToString(uname.Machine) == "arm" { + machine = "arm" + } else if ArrayToString(uname.Machine) == "arm64" { + machine = "arm64" + } else if ArrayToString(uname.Machine) == "x86_64" { + machine = "amd64" + } else { + machine = "UNKNOWN" + fmt.Println("Unknown machine") + } + + url := "https://storage.googleapis.com/kubernetes-release/release/" + version + "/bin/" + sys + "/" + machine + "/kubectl" + + resp, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + defer resp.Body.Close() + + // Initialise WriteCounter and copy the contents of the response body to the tmp file + counter := &WriteCounter{} + _, err = io.Copy(out, io.TeeReader(resp.Body, counter)) + if err != nil { + log.Fatal(err) + } + + // The progress use the same line so print a new line once it's finished downloading + fmt.Println() + + // Set executable permissions on the kubectl binary + if err := os.Chmod(homeDir+"/.kubemngr/kubectl-"+version+".tmp", 0755); err != nil { + log.Fatal(err) + } + + // Rename the tmp file back to the original file and store it in the kubemngr directory + currentFilePath := homeDir + "/.kubemngr/kubectl-" + version + ".tmp" + newFilePath := homeDir + "/.kubemngr/kubectl-" + version + + err = os.Rename(currentFilePath, newFilePath) + if err != nil { + log.Fatal(err) + } + + return nil +} + +// GetOSInfo - Get operating system information of machine +func GetOSInfo() syscall.Utsname { + var uname syscall.Utsname + + if err := syscall.Uname(&uname); err != nil { + fmt.Printf("Uname: %v", err) + } + + return uname +} + +func (wc *WriteCounter) Write(p []byte) (int, error) { + n := len(p) + wc.Total += uint64(n) + wc.PrintProgress() + return n, nil +} + +// PrintProgress - Helper function to print progress of a download +func (wc WriteCounter) PrintProgress() { + // Clear the line by using a character return to go back to the start and remove + // the remaining characters by filling it with spaces + fmt.Printf("\r%s", strings.Repeat(" ", 50)) + + // Return again and print current status of download + // We use the humanize package to print the bytes in a meaningful way (e.g. 10 MB) + fmt.Printf("\rDownloading... %s complete", humanize.Bytes(wc.Total)) +} + +func ArrayToString(x [65]int8) string { + var buf [65]byte + for i, b := range x { + buf[i] = byte(b) + } + str := string(buf[:]) + if i := strings.Index(str, "\x00"); i != -1 { + str = str[:i] + } + return str +} diff --git a/cmd/install.go b/cmd/install_linux.go similarity index 99% rename from cmd/install.go rename to cmd/install_linux.go index e93db1c..edef087 100644 --- a/cmd/install.go +++ b/cmd/install_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE diff --git a/cmd/listRemote_darwin.go b/cmd/listRemote_darwin.go new file mode 100644 index 0000000..bc07db9 --- /dev/null +++ b/cmd/listRemote_darwin.go @@ -0,0 +1,92 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +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 ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "strings" + + "github.com/spf13/cobra" +) + +type Kubernetes []struct { + TagName string `json:"tag_name"` +} + +// listRemoteCmd represents the listRemote command +var listRemoteCmd = &cobra.Command{ + Use: "listRemote", + Short: "List available remote kubectl versions to download and install", + Run: func(cmd *cobra.Command, args []string) { + + fmt.Println("Getting available list of kubectl versions to install") + + k8s := Kubernetes{} + _ = ListAvailableRemotes("https://api.github.com/repos/kubernetes/kubernetes/releases?per_page=100", &k8s) + + for _, releases := range k8s { + version := releases.TagName + + // filter out alpha and release candidatest and only show stable releases + filterStable := strings.NewReplacer("-rc.1", "", "-beta.2", "", "-beta.1", "", "-alpha.3", "", "-alpha.2", "", "-alpha.1", "", "-rc.2", "", "-rc.3", "") + stable := filterStable.Replace(version) + + fmt.Println(stable) + } + }, +} + +func init() { + rootCmd.AddCommand(listRemoteCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // listRemoteCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // listRemoteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +func ListAvailableRemotes(url string, target interface{}) error { + + res, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + + defer res.Body.Close() + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + log.Fatal(err) + } + + jsonErr := json.Unmarshal(body, &target) + if jsonErr != nil { + log.Fatal(jsonErr) + } + + return jsonErr +} diff --git a/cmd/listRemote.go b/cmd/listRemote_linux.go similarity index 99% rename from cmd/listRemote.go rename to cmd/listRemote_linux.go index 4039cfe..6e38e5d 100644 --- a/cmd/listRemote.go +++ b/cmd/listRemote_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE diff --git a/cmd/list_darwin.go b/cmd/list_darwin.go new file mode 100644 index 0000000..61f8420 --- /dev/null +++ b/cmd/list_darwin.go @@ -0,0 +1,81 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "strings" + + "github.com/spf13/cobra" +) + +// listCmd represents the list command +var listCmd = &cobra.Command{ + Use: "list", + Short: "List downloaded kubectl binaries", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Retrieving installed versions of kubectl") + + err := ListKubectlBinaries() + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + rootCmd.AddCommand(listCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // listCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // listCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// ListKubectlBinaries - List available installed kubectl versions +func ListKubectlBinaries() error { + + // Get user home directory path + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal(err) + } + + // Read kubemngr directory + kubectl, err := ioutil.ReadDir(homeDir + "/.kubemngr/") + if err != nil { + log.Fatal(err) + } + + // iterate and print files inside the kubemngr directory + for _, files := range kubectl { + file := files.Name() + version := strings.Replace(file, "kubectl-", "", -1) + fmt.Println(version) + } + + return nil +} diff --git a/cmd/list.go b/cmd/list_linux.go similarity index 99% rename from cmd/list.go rename to cmd/list_linux.go index 626fd5f..dcd8d53 100644 --- a/cmd/list.go +++ b/cmd/list_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE diff --git a/cmd/remove_darwin.go b/cmd/remove_darwin.go new file mode 100644 index 0000000..515f348 --- /dev/null +++ b/cmd/remove_darwin.go @@ -0,0 +1,74 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +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" + "log" + "os" + + "github.com/spf13/cobra" +) + +// removeCmd represents the remove command +var removeCmd = &cobra.Command{ + Use: "remove", + Short: "Remove a kubectl version from machine", + Run: func(cmd *cobra.Command, args []string) { + err := RemoveKubectlVersion(args[0]) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + rootCmd.AddCommand(removeCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // removeCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // removeCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// RemoveKubectlVersion - removes specific kubectl version from machine +func RemoveKubectlVersion(version string) error { + // Get user home directory path + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal(err) + } + + kubectlVersion := homeDir + "/.kubemngr/kubectl-" + version + + // Check if version exists to remove it + _, err = os.Stat(kubectlVersion) + if err == nil { + fmt.Printf("Removing kubectl %s", version) + os.Remove(kubectlVersion) + return nil + } else { + fmt.Printf("kubectl version %s doesn't exist", version) + return nil + } +} diff --git a/cmd/remove.go b/cmd/remove_linux.go similarity index 99% rename from cmd/remove.go rename to cmd/remove_linux.go index 64bccd9..05af8dc 100644 --- a/cmd/remove.go +++ b/cmd/remove_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE diff --git a/cmd/root.go b/cmd/root_darwin.go similarity index 99% rename from cmd/root.go rename to cmd/root_darwin.go index 9b4b1ca..c7950c5 100644 --- a/cmd/root.go +++ b/cmd/root_darwin.go @@ -1,3 +1,5 @@ +// +build darwin + /* Copyright © 2019 NAME HERE diff --git a/cmd/root_linux.go b/cmd/root_linux.go new file mode 100644 index 0000000..97fc3d4 --- /dev/null +++ b/cmd/root_linux.go @@ -0,0 +1,93 @@ +// +build linux + +/* +Copyright © 2019 NAME HERE + +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" + + "github.com/spf13/cobra" + + homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/viper" +) + +var cfgFile string +var clientVersion string + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "kubemngr", + Short: "A tool manage different kubectl versions inside a workspace.", + Long: `This tool is to help developers run different versions of kubectl within their workspace and to support working +with different versions of Kubernetes clusters.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute(version string) { + clientVersion = version + + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.kubemngr.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Search config in home directory with name ".kubemngr" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".kubemngr") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/cmd/use_darwin.go b/cmd/use_darwin.go new file mode 100644 index 0000000..386cb7c --- /dev/null +++ b/cmd/use_darwin.go @@ -0,0 +1,77 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +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" + "log" + "os" + + "github.com/spf13/cobra" +) + +// useCmd represents the use command +var useCmd = &cobra.Command{ + Use: "use", + Short: "Use a specific version of one of the downloaded kubectl binaries", + Run: func(cmd *cobra.Command, args []string) { + err := UseKubectlBinary(args[0]) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + rootCmd.AddCommand(useCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // useCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // useCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// UseKubectlBinary - sets kubectl to the version specified +func UseKubectlBinary(version string) error { + + homeDir, err := os.UserHomeDir() + if err != nil { + log.Fatal(err) + } + + kubectlVersion := homeDir + "/.kubemngr/kubectl-" + version + kubectlLink := homeDir + "/.local/bin/kubectl" + + if _, err := os.Lstat(kubectlLink); err == nil { + os.Remove(kubectlLink) + } + + err = os.Symlink(kubectlVersion, kubectlLink) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("kubectl version set to %s", version) + + return nil +} diff --git a/cmd/use.go b/cmd/use_linux.go similarity index 99% rename from cmd/use.go rename to cmd/use_linux.go index d55fd13..b0f6c4a 100644 --- a/cmd/use.go +++ b/cmd/use_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE diff --git a/cmd/version_darwin.go b/cmd/version_darwin.go new file mode 100644 index 0000000..d02b003 --- /dev/null +++ b/cmd/version_darwin.go @@ -0,0 +1,37 @@ +// +build darwin + +/* +Copyright © 2019 NAME HERE + +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" + + "github.com/spf13/cobra" +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Show the kubemngr client version", + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(rootCmd.Use + " " + clientVersion) + }, +} + +func init() { + rootCmd.AddCommand(versionCmd) +} diff --git a/cmd/version.go b/cmd/version_linux.go similarity index 98% rename from cmd/version.go rename to cmd/version_linux.go index b27a7a9..5e636ae 100644 --- a/cmd/version.go +++ b/cmd/version_linux.go @@ -1,3 +1,5 @@ +// +build linux + /* Copyright © 2019 NAME HERE