├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── cmd ├── install.go ├── list.go ├── main.go ├── remove.go ├── root.go └── version.go ├── github └── github.go ├── go.mod ├── go.sum ├── hack └── image-tag.sh └── terraform ├── exist.go ├── init.go ├── install.go ├── list.go ├── terraform.go ├── types.go ├── uninstall.go └── uninstall_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | .vscode/settings.json 27 | debug.log 28 | build/ 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 PERRIER A. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: tfversion release clean test race graph 2 | 3 | GOLANG_ENV?=CGO_ENABLED=0 4 | IMAGE_TAG:=$(shell ./hack/image-tag.sh) 5 | LDFLAGS?=-v -ldflags="-w -s -X main.version=$(IMAGE_TAG)" 6 | TEST_FLAGS?= 7 | PKG_LIST := $(shell go list ./... | sort -u) 8 | 9 | # NB default target architecture is amd64. If you would like to try the 10 | # other one -- pass an ARCH variable, e.g., 11 | # `make ARCH=arm64` 12 | ifeq ($(ARCH),) 13 | ARCH=amd64 14 | endif 15 | 16 | all: tfversion 17 | 18 | tfversion: 19 | $(GOLANG_ENV) go build $(LDFLAGS) -o build/tfversion $(PWD)/cmd 20 | 21 | release: 22 | for arch in amd64; do \ 23 | for os in linux darwin; do \ 24 | $(GOLANG_ENV) GOOS=$$os GOARCH=$$arch go build -o "build/tfversion_"$$os"_$$arch" $(LDFLAGS) -ldflags "-X main.version=$(IMAGE_TAG)" $(PWD)/cmd; \ 25 | done; \ 26 | done; 27 | 28 | clean: 29 | go clean 30 | rm -rf ./build 31 | 32 | race: 33 | go test -race -coverprofile=coverage.txt -covermode=atomic ${PKG_LIST} 34 | 35 | graph: 36 | go-callvis -file=data -format=png -group pkg -focus="" -limit github.com/perriea/tfversion $(PWD)/cmd 37 | 38 | test: 39 | go test ${TEST_FLAGS} ${PKG_LIST} 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tfversion 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/perriea/tfversion)](https://goreportcard.com/report/github.com/perriea/tfversion) [![Build Status](https://travis-ci.org/perriea/tfversion.svg?branch=master)](https://travis-ci.org/perriea/tfversion) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 3 | 4 | `tfversion` is a command created to switch between different versions of [Terraform](https://www.terraform.io). 5 | 6 | ## Build Project 7 | 8 | - [Install Golang](https://golang.org/doc/install) (add var ENV), 9 | - Build with commands `go build`, `make` or `go get -u github.com/perriea/tfversion`, 10 | - Add in your `.bashrc` (Linux), `.bash_profile` (Darwin, MacOS) or `.zshrc` : `export PATH=$PATH:$HOME/.tfversion/bin`. 11 | 12 | ## Commands 13 | 14 | ``` shell 15 | ➜ ~ ✗ tfversion 16 | tfversion v0.1.6 - Switcher Terraform 17 | 18 | Usage: 19 | tfversion [command] 20 | 21 | Available Commands: 22 | help Help about any command 23 | install Install new versions or switch 24 | list List of terraform versions 25 | remove Remove local version of Terraform 26 | version Version installed of switcher Terraform 27 | 28 | Flags: 29 | -h, --help help for tfversion 30 | 31 | Use "tfversion [command] --help" for more information about a command. 32 | ``` 33 | 34 | ## License 35 | 36 | The MIT License (MIT) 37 | Copyright (c) 2017-2020 Aurelien PERRIER 38 | -------------------------------------------------------------------------------- /cmd/install.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | // installCmd represents the install command 8 | var installCmd = &cobra.Command{ 9 | Use: "install [version]", 10 | Short: "Install a new version", 11 | Long: `Install a new version or switch.`, 12 | PreRunE: func(cmd *cobra.Command, args []string) error { 13 | return r.InitFolder() 14 | }, 15 | RunE: func(cmd *cobra.Command, args []string) error { 16 | return r.Run(args, quiet) 17 | }, 18 | } 19 | 20 | func init() { 21 | rootCmd.AddCommand(installCmd) 22 | installCmd.Flags().BoolVarP(&quiet, "quiet", "q", false, "Do not show information messages") 23 | } 24 | -------------------------------------------------------------------------------- /cmd/list.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | // listCmd represents the list command 8 | var listCmd = &cobra.Command{ 9 | Use: "list", 10 | Short: "List of available versions", 11 | Long: `List of available versions`, 12 | Run: func(cmd *cobra.Command, args []string) { 13 | if err = r.ListOnline(); err != nil { 14 | panic(err) 15 | } 16 | }, 17 | } 18 | 19 | func init() { 20 | rootCmd.AddCommand(listCmd) 21 | } 22 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var version string 4 | 5 | func main() { 6 | Execute() 7 | } 8 | -------------------------------------------------------------------------------- /cmd/remove.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | ) 6 | 7 | // removeCmd represents the remove command 8 | var removeCmd = &cobra.Command{ 9 | Use: "remove [version]", 10 | Short: "Remove local version of Terraform", 11 | Long: `Remove local version of Terraform`, 12 | RunE: func(cmd *cobra.Command, args []string) error { 13 | // Check argument number 14 | if len(args) > 0 && !all { 15 | // affect value version 16 | r.Version = args[0] 17 | if r.Regex() { 18 | return r.UnInstall(quiet) 19 | } 20 | } else if len(args) == 0 && all { 21 | return r.UnInstallAll(quiet) 22 | } 23 | 24 | return nil 25 | }, 26 | } 27 | 28 | func init() { 29 | rootCmd.AddCommand(removeCmd) 30 | removeCmd.Flags().BoolVarP(&all, "all", "a", false, "Remove all version of Terraform") 31 | removeCmd.Flags().BoolVarP(&quiet, "quiet", "q", false, "Do not show information messages") 32 | } 33 | -------------------------------------------------------------------------------- /cmd/root.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/perriea/tfversion/terraform" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | var ( 12 | r *terraform.Release = terraform.NewRelease() 13 | home, cfgFile string 14 | quiet, all bool 15 | err error 16 | ) 17 | 18 | // rootCmd represents the base command when called without any subcommands 19 | var rootCmd = &cobra.Command{ 20 | Use: "tfversion", 21 | Short: fmt.Sprintf("tfversion %s - Switcher Terraform", version), 22 | Long: fmt.Sprintf("tfversion %s - Switcher Terraform", version), 23 | } 24 | 25 | // Execute adds all child commands to the root command and sets flags appropriately. 26 | // This is called by main.main(). It only needs to happen once to the rootCmd. 27 | func Execute() { 28 | if err = rootCmd.Execute(); err != nil { 29 | fmt.Println(err) 30 | os.Exit(1) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | 7 | "github.com/perriea/tfversion/github" 8 | "github.com/spf13/cobra" 9 | ) 10 | 11 | // versionCmd represents the version command 12 | var versionCmd = &cobra.Command{ 13 | Use: "version", 14 | Short: "Version installed", 15 | Long: `Version installed of switcher Terraform`, 16 | Run: func(cmd *cobra.Command, args []string) { 17 | fmt.Printf("tfversion %s\n\n", version) 18 | 19 | // Show if the last version 20 | latest, release := github.LastVersion(version) 21 | if latest && release != nil { 22 | switch runtime.GOOS { 23 | case "darwin": 24 | fmt.Printf("Your version is out of date ! The latest version is %s.\nYou can update with brew.", *release.TagName) 25 | case "linux": 26 | fmt.Printf("Your version is out of date ! The latest version is %s.\nYou can update with snap (Ubuntu) or download from Github (%s).", *release.TagName, *release.HTMLURL) 27 | default: 28 | fmt.Printf("You are strange man ! :D") 29 | } 30 | } 31 | }, 32 | } 33 | 34 | func init() { 35 | rootCmd.AddCommand(versionCmd) 36 | } 37 | -------------------------------------------------------------------------------- /github/github.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/google/go-github/github" 7 | pversion "github.com/hashicorp/go-version" 8 | ) 9 | 10 | // LastVersion : Check last version of package 11 | func LastVersion(version string) (bool, *github.RepositoryRelease) { 12 | var ( 13 | semVer = pversion.Must(pversion.NewVersion(version)) 14 | ctx context.Context = context.Background() 15 | client *github.Client = github.NewClient(nil) 16 | releases []*github.RepositoryRelease 17 | err error 18 | ) 19 | 20 | if releases, _, err = client.Repositories.ListReleases(ctx, "perriea", "tfversion", nil); err != nil { 21 | panic(err) 22 | } 23 | 24 | if len(releases) > 0 { 25 | lastRelease, _ := pversion.NewVersion(*releases[0].TagName) 26 | if semVer.LessThan(lastRelease) { 27 | return true, releases[0] 28 | } 29 | } 30 | 31 | return false, nil 32 | } 33 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/perriea/tfversion 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/google/go-github v17.0.0+incompatible 7 | github.com/google/go-querystring v1.0.0 // indirect 8 | github.com/hashicorp/go-version v1.2.0 9 | github.com/mitchellh/go-homedir v1.1.0 10 | github.com/ryanuber/columnize v2.1.0+incompatible 11 | github.com/spf13/cobra v1.0.0 12 | ) 13 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 4 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 5 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 6 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 7 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 8 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 9 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 10 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 11 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 12 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 13 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 14 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 15 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 16 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 17 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 19 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 20 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 21 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 22 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 23 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 24 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 25 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 26 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 27 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 28 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 29 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 30 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 31 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 32 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 33 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 34 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 35 | github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= 36 | github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 37 | github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= 38 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 39 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 40 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 41 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 42 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 43 | github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= 44 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 45 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 46 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= 47 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 48 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 49 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 50 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 51 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 52 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 53 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 54 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 55 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 56 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 57 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 58 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 59 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 60 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 61 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 62 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 63 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 64 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 65 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 66 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 67 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 68 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 69 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 70 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 71 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 72 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 73 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 74 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 75 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 76 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 77 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 78 | github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= 79 | github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 80 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 81 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 82 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 83 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 84 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 85 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 86 | github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= 87 | github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= 88 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 89 | github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= 90 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 91 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= 92 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 93 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 94 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 95 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= 96 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 97 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 98 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 99 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 100 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 101 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 102 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 103 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 104 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 105 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 106 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 107 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 108 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 109 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 110 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 111 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 112 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 113 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 114 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 115 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 116 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 117 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 118 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 119 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 120 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 121 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 122 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 123 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 124 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 125 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 126 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 127 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 128 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 129 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 130 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 131 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 132 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 133 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 134 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 135 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 136 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 137 | -------------------------------------------------------------------------------- /hack/image-tag.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | OUTPUT=--quiet 8 | if [ "${1:-}" = '--show-diff' ]; then 9 | OUTPUT= 10 | fi 11 | 12 | # If a tagged version, just print that tag 13 | HEAD_TAGS=$(git tag --points-at HEAD) 14 | if [ -n "${HEAD_TAGS}" ] ; then 15 | if echo "${HEAD_TAGS}" | grep -Eq "helm-[0-9]+(\.[0-9]+)*(-[a-z]+)?$"; then 16 | HEAD_TAGS=$(echo "$HEAD_TAGS" | cut -c 6-) 17 | fi 18 | echo ${HEAD_TAGS} 19 | exit 0 20 | fi 21 | 22 | 23 | WORKING_SUFFIX=$(if ! git diff --exit-code ${OUTPUT} HEAD >&2; \ 24 | then echo "-wip"; \ 25 | else echo ""; \ 26 | fi) 27 | BRANCH_PREFIX=$(git rev-parse --abbrev-ref HEAD) 28 | 29 | # replace spaces with dash 30 | BRANCH_PREFIX=${BRANCH_PREFIX// /-} 31 | # next, replace slashes with dash 32 | BRANCH_PREFIX=${BRANCH_PREFIX//[\/\\]/-} 33 | # now, clean out anything that's not alphanumeric or an dash 34 | BRANCH_PREFIX=${BRANCH_PREFIX//[^a-zA-Z0-9-]/} 35 | # finally, lowercase with TR 36 | BRANCH_PREFIX=`echo -n $BRANCH_PREFIX | tr A-Z a-z` 37 | 38 | echo "$BRANCH_PREFIX-$(git rev-parse --short HEAD)$WORKING_SUFFIX" -------------------------------------------------------------------------------- /terraform/exist.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | "path/filepath" 8 | "regexp" 9 | "runtime" 10 | ) 11 | 12 | // Regex version submited 13 | func (r *Release) Regex() bool { 14 | var ( 15 | rmatch string = "[0-9]+\\.[0-9]+\\.[0-9]+(-(rc|beta|alpha)[0-9]+)?" 16 | match bool = false 17 | err error 18 | ) 19 | 20 | if match, err = regexp.MatchString(rmatch, r.Version); err != nil { 21 | return false 22 | } 23 | 24 | return match 25 | } 26 | 27 | // localExist version zipped offline 28 | func (r *Release) localExist() error { 29 | var ( 30 | version string = fmt.Sprintf("terraform-%s.zip", r.Version) 31 | err error 32 | ) 33 | 34 | if _, err = os.Stat(filepath.Join(r.Home, PathTmp.toString(), version)); !os.IsNotExist(err) { 35 | fmt.Println("Already in cache ...") 36 | return err 37 | } 38 | 39 | return nil 40 | } 41 | 42 | // remoteExist version zipped online 43 | func (r *Release) remoteExist() error { 44 | var ( 45 | url string = fmt.Sprintf(PathTerraform.toString(), r.Version, r.Version, runtime.GOOS, runtime.GOARCH) 46 | resp *http.Response 47 | err error 48 | ) 49 | 50 | if resp, err = r.HTTPclient.Get(url); err != nil { 51 | return err 52 | } 53 | defer resp.Body.Close() 54 | 55 | // Verify code equal 200 56 | if resp.StatusCode == http.StatusOK { 57 | return nil 58 | } 59 | 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /terraform/init.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | // CreateFolder on disk 10 | func (r *Release) CreateFolder(folder string) error { 11 | var err error 12 | 13 | if err = os.MkdirAll(filepath.Join(r.Home, folder), os.FileMode(0755)); err != nil { 14 | return err 15 | } 16 | 17 | return nil 18 | } 19 | 20 | // InitFolder : Create folders (init) 21 | func (r *Release) InitFolder() error { 22 | var err error 23 | 24 | if err = r.CreateFolder(PathBin.toString()); err != nil { 25 | return err 26 | } 27 | 28 | if err = r.CreateFolder(PathTmp.toString()); err != nil { 29 | return err 30 | } 31 | 32 | return nil 33 | } 34 | 35 | // Message : Quiet mode 36 | func Message(message string, quiet bool) { 37 | if !quiet { 38 | fmt.Println(message) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /terraform/install.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "archive/zip" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "os" 11 | "path/filepath" 12 | "runtime" 13 | ) 14 | 15 | // Download : Launch download 16 | func (r *Release) download(quiet bool) error { 17 | var ( 18 | url string = fmt.Sprintf(PathTerraform.toString(), r.Version, r.Version, runtime.GOOS, runtime.GOARCH) 19 | path string = fmt.Sprintf("%s%sterraform-%s.zip", r.Home, PathTmp.toString(), r.Version) 20 | resp *http.Response 21 | fileUnzip *os.File 22 | err error 23 | ) 24 | 25 | // Request GET URL 26 | if resp, err = r.HTTPclient.Get(url); err != nil { 27 | return err 28 | } 29 | defer resp.Body.Close() 30 | 31 | // Verify code equal 200 32 | if resp.StatusCode == http.StatusOK { 33 | Message("Downloading ...", quiet) 34 | 35 | if fileUnzip, err = os.Create(path); err != nil { 36 | return err 37 | } 38 | defer fileUnzip.Close() 39 | 40 | // Copy reponse in file 41 | _, err = io.Copy(fileUnzip, resp.Body) 42 | 43 | return err 44 | } 45 | 46 | return errors.New("failed, this version doesn't exist") 47 | } 48 | 49 | // UnZipFile : UnZip one file 50 | func (r *Release) unZip(archive string, target string) error { 51 | var ( 52 | path string 53 | fileReader io.ReadCloser 54 | reader *zip.ReadCloser 55 | targetFile *os.File 56 | err error 57 | ) 58 | 59 | if reader, err = zip.OpenReader(filepath.Join(archive)); err != nil { 60 | return err 61 | } 62 | 63 | for _, file := range reader.File { 64 | path = filepath.Join(target, file.Name) 65 | if file.FileInfo().IsDir() { 66 | os.MkdirAll(path, file.Mode()) 67 | continue 68 | } 69 | 70 | if fileReader, err = file.Open(); err != nil { 71 | return err 72 | } 73 | defer fileReader.Close() 74 | 75 | if targetFile, err = os.OpenFile(filepath.Join(r.Home, PathBin.toString(), "terraform"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()); err != nil { 76 | return err 77 | } 78 | defer targetFile.Close() 79 | 80 | _, err = io.Copy(targetFile, fileReader) 81 | 82 | return err 83 | } 84 | 85 | return err 86 | } 87 | 88 | // Install Terraform versions 89 | func (r *Release) install(quiet bool) error { 90 | var ( 91 | err error 92 | ) 93 | 94 | // UnZip archive 95 | Message("Installing ...", quiet) 96 | if err = r.unZip(filepath.Join(r.Home, PathTmp.toString(), fmt.Sprintf("/terraform-%s.zip", r.Version)), filepath.Join(r.Home, PathBin.toString())); err != nil { 97 | return err 98 | } 99 | 100 | // Save version in file 101 | if err = ioutil.WriteFile(filepath.Join(r.Home, PathTmp.toString(), ".version"), []byte(r.Version), 0600); err != nil { 102 | return err 103 | } 104 | 105 | Message(fmt.Sprintf("v%s installed ♥", r.Version), quiet) 106 | 107 | return nil 108 | } 109 | -------------------------------------------------------------------------------- /terraform/list.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net/http" 7 | "regexp" 8 | 9 | "github.com/ryanuber/columnize" 10 | ) 11 | 12 | func stringInSlice(str string, list []string) bool { 13 | for _, v := range list { 14 | if v == str { 15 | return true 16 | } 17 | } 18 | 19 | return false 20 | } 21 | 22 | func showList(list []string, tfversion string) { 23 | var max, i, k int 24 | 25 | i = 0 26 | max = 10 27 | reslist := []string{} 28 | 29 | for i < len(list) { 30 | newlist := "" 31 | for k <= max { 32 | if (k != max) && (len(list)-i) > 0 { 33 | if list[i] == tfversion { 34 | newlist = fmt.Sprintf("\033[0;37m%s\033[1;32m%s\033[0;37m | ", newlist, list[i]) 35 | } else { 36 | newlist = fmt.Sprintf("\033[0;37m%s%s | ", newlist, list[i]) 37 | } 38 | } else { 39 | if (len(list) - i) >= 0 { 40 | reslist = append(reslist, newlist) 41 | } 42 | } 43 | 44 | k++ 45 | i++ 46 | } 47 | 48 | k = 0 49 | } 50 | 51 | result := columnize.SimpleFormat(reslist) 52 | fmt.Println(result) 53 | } 54 | 55 | // ListOnline : List online version 56 | func (r *Release) ListOnline() error { 57 | var ( 58 | versions, cleaned []string 59 | resp *http.Response 60 | err error 61 | ) 62 | 63 | // Request GET URL 64 | if resp, err = r.HTTPclient.Get(PathTerraformIndex.toString()); err != nil { 65 | return err 66 | } 67 | defer resp.Body.Close() 68 | 69 | // Verify code equal 200 70 | if (err == nil) && (resp.StatusCode == http.StatusOK) { 71 | r, err := regexp.Compile("[0-9]+\\.[0-9]+\\.[0-9]+(-(rc|beta|alpha)[0-9]+)?") 72 | if err != nil { 73 | return err 74 | } 75 | 76 | // Convert byte to string 77 | buf := new(bytes.Buffer) 78 | buf.ReadFrom(resp.Body) 79 | newStr := buf.String() 80 | 81 | fmt.Printf("Versions available of Terraform :\n") 82 | versions = r.FindAllString(newStr, -1) 83 | 84 | // Clean doublon 85 | for _, value := range versions { 86 | if !stringInSlice(value, cleaned) { 87 | cleaned = append(cleaned, value) 88 | } 89 | } 90 | 91 | // Show versions 92 | showList(cleaned, "0") 93 | } 94 | 95 | return nil 96 | } 97 | -------------------------------------------------------------------------------- /terraform/terraform.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "crypto/tls" 5 | "errors" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/mitchellh/go-homedir" 10 | ) 11 | 12 | func (r *Release) Run(args []string, quiet bool) error { 13 | var ( 14 | nArg int = len(args) 15 | err error 16 | ) 17 | 18 | // Check argument number 19 | if nArg > 0 { 20 | // affect value version 21 | r.Version = args[0] 22 | 23 | // Check this value 24 | if r.Regex() { 25 | // Check if r is stocked in localy & remotely 26 | if err = r.localExist(); err != nil { 27 | return r.install(quiet) 28 | } else if err = r.remoteExist(); err == nil { 29 | if err = r.download(quiet); err != nil { 30 | return err 31 | } 32 | 33 | if err := r.install(quiet); err != nil { 34 | return err 35 | } 36 | 37 | return nil 38 | } 39 | 40 | return nil 41 | } 42 | 43 | return errors.New("format version invalid") 44 | } 45 | 46 | return errors.New("Argument(s) missing") 47 | } 48 | 49 | // NewRelease Client 50 | func NewRelease() *Release { 51 | var ( 52 | home string 53 | err error 54 | ) 55 | 56 | if home, err = homedir.Dir(); err != nil { 57 | panic(err) 58 | } 59 | 60 | return &Release{ 61 | Home: home, 62 | HTTPclient: &http.Client{ 63 | Transport: &http.Transport{ 64 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 65 | }, 66 | Timeout: time.Duration(60 * time.Second), 67 | }, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /terraform/types.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import "net/http" 4 | 5 | // Release struct : information switch release 6 | type Release struct { 7 | Home string 8 | Version string 9 | HTTPclient *http.Client 10 | HTTPResponse *http.Response 11 | } 12 | 13 | type Path string 14 | 15 | const ( 16 | PathTerraform Path = "https://releases.hashicorp.com/terraform/%s/terraform_%s_%s_%s.zip" 17 | PathTerraformIndex Path = "https://releases.hashicorp.com/terraform/" 18 | PathBin Path = "/.tfversion/bin/" 19 | PathTmp Path = "/.tfversion/tmp/" 20 | ) 21 | 22 | func (f Path) toString() string { 23 | return string(f) 24 | } 25 | -------------------------------------------------------------------------------- /terraform/uninstall.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // UnInstallAll Terraform versions 11 | func (r *Release) UnInstallAll(quiet bool) error { 12 | var ( 13 | files []os.FileInfo 14 | count int 15 | err error 16 | ) 17 | 18 | if files, err = ioutil.ReadDir(filepath.Join(r.Home, PathTmp.toString())); err != nil { 19 | return err 20 | } 21 | 22 | for _, file := range files { 23 | if err = os.Remove(filepath.Join(r.Home, PathTmp.toString(), file.Name())); err != nil { 24 | return err 25 | } 26 | 27 | count++ 28 | } 29 | 30 | if count == 0 { 31 | Message("No version has been removed", quiet) 32 | } else { 33 | Message("All versions have been removed", quiet) 34 | } 35 | 36 | return nil 37 | } 38 | 39 | // UnInstall Terraform version 40 | func (r *Release) UnInstall(quiet bool) error { 41 | var ( 42 | files []os.FileInfo 43 | count int 44 | err error 45 | ) 46 | 47 | if files, err = ioutil.ReadDir(filepath.Join(r.Home, PathTmp.toString())); err != nil { 48 | return err 49 | } 50 | 51 | for _, file := range files { 52 | if file.Name() == fmt.Sprintf("terraform-%s.zip", r.Version) { 53 | if err = os.Remove(filepath.Join(r.Home, PathTmp.toString(), file.Name())); err != nil { 54 | return err 55 | } 56 | 57 | Message(fmt.Sprintf("Version %s is deleted !\n", r.Version), quiet) 58 | return nil 59 | } 60 | 61 | count++ 62 | } 63 | 64 | if count == 0 { 65 | Message("No version has been removed", quiet) 66 | } else { 67 | Message("All versions have been removed", quiet) 68 | } 69 | 70 | return nil 71 | } 72 | -------------------------------------------------------------------------------- /terraform/uninstall_test.go: -------------------------------------------------------------------------------- 1 | package terraform 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "net/http" 7 | "testing" 8 | 9 | homedir "github.com/mitchellh/go-homedir" 10 | ) 11 | 12 | // TestUnInstall : testing installation 13 | func TestUnInstall(t *testing.T) { 14 | var ( 15 | home string 16 | versions []string 17 | err error 18 | ) 19 | 20 | versions = []string{"0.11.0", "0.11.0-beta1", "0.11.0-rc1", "0.10.8", "0.7.2", "0.1.0"} 21 | 22 | home, err = homedir.Dir() 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | for _, version := range versions { 28 | 29 | release := Release{ 30 | Home: home, 31 | Version: version, 32 | HTTPclient: &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}, 33 | Repository: "releases.hashicorp.com/terraform/%s/terraform_%s_%s_%s.zip", 34 | } 35 | 36 | err = release.UnInstall(true) 37 | if err != nil { 38 | t.Fatalf("uninstall failed (%s)\n", version) 39 | } else { 40 | fmt.Printf("uninstall OK (%s)\n", version) 41 | } 42 | } 43 | } 44 | --------------------------------------------------------------------------------