Skip to content

Commit

Permalink
refactor code
Browse files Browse the repository at this point in the history
prepared the system to handle not only Terraform but also Opentofu.
  • Loading branch information
cappyzawa committed Apr 29, 2024
1 parent 7e49007 commit 5477b25
Show file tree
Hide file tree
Showing 10 changed files with 217 additions and 190 deletions.
15 changes: 5 additions & 10 deletions cmd/tfswitch/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ package main

import (
"io"
"net/http"
"os"
"runtime/debug"

"github.com/cappyzawa/tfswitch/v2/internal/command"
"github.com/cappyzawa/tfswitch/v2/internal/di"
"github.com/mitchellh/cli"
)

Expand Down Expand Up @@ -36,15 +35,11 @@ func (r *runnner) Run(args []string) int {
}
c := cli.NewCLI(args[0], version)
c.Args = args[1:]
factories := command.Factories{
UI: ui,
DataHome: r.dataHome,
HttpClient: http.DefaultClient,
}
dc := di.NewContainer(ui, r.dataHome)
c.Commands = map[string]cli.CommandFactory{
"use": factories.Use,
"local-list": factories.LocalList,
"remote-list": factories.RemoteList,
"use": dc.UseCommand,
"local-list": dc.LocalListCommand,
"remote-list": dc.RemoteListCommand,
}
exitStatus, err := c.Run()
if err != nil {
Expand Down
39 changes: 0 additions & 39 deletions internal/command/command.go

This file was deleted.

20 changes: 10 additions & 10 deletions internal/command/local-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import (
"github.com/mitchellh/cli"
)

type localListCommand struct {
ui *cli.ColoredUi
dataHome string
type LocalListCommand struct {
UI *cli.ColoredUi
DataHome string
}

func (c *localListCommand) Help() string {
func (c *LocalListCommand) Help() string {
return `This command displays available versions in local.
Usage:
Expand All @@ -31,29 +31,29 @@ Examples:
`
}

func (c *localListCommand) Run(args []string) int {
func (c *LocalListCommand) Run(args []string) int {
var filter string
flags := flag.NewFlagSet("", flag.ExitOnError)
flags.StringVar(&filter, "filter", "", "Filter by the specified version (Prefix Match)")
if err := flags.Parse(args); err != nil {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 1
}

tfDataPATH := filepath.Join(c.dataHome, "tfswitch")
tfDataPATH := filepath.Join(c.DataHome, "tfswitch")
if d, err := os.Stat(tfDataPATH); os.IsNotExist(err) || !d.IsDir() {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 1
}
files, _ := os.ReadDir(tfDataPATH)
for _, f := range files {
if f.IsDir() && strings.HasPrefix(f.Name(), filter) {
c.ui.Output(f.Name())
c.UI.Output(f.Name())
}
}
return 0
}

func (c *localListCommand) Synopsis() string {
func (c *LocalListCommand) Synopsis() string {
return "display available terraform versions in local."
}
68 changes: 11 additions & 57 deletions internal/command/remote-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@ package command

import (
"flag"
"fmt"
"net/http"
"net/url"
"strings"

"github.com/PuerkitoBio/goquery"
"github.com/cappyzawa/tfswitch/v2/internal/repository"
"github.com/mitchellh/cli"
)

type remoteListCommand struct {
ui *cli.ColoredUi
httpClient *http.Client
type RemoteListCommand struct {
UI *cli.ColoredUi
Client repository.Client
}

func (c *remoteListCommand) Help() string {
func (c *RemoteListCommand) Help() string {
return `This command displays available versions in remote. (https://releases.hashicorp.com/terraform/)
Usage:
Expand All @@ -33,71 +30,28 @@ Examples:
`
}

func (c *remoteListCommand) Run(args []string) int {
func (c *RemoteListCommand) Run(args []string) int {
var filter string
flags := flag.NewFlagSet("", flag.ExitOnError)
flags.StringVar(&filter, "filter", "", "Filter by the specified version (Prefix Match)")
if err := flags.Parse(args); err != nil {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 1
}

cc := &client{
url: &url.URL{
Scheme: "https",
Host: "releases.hashicorp.com",
Path: "terraform",
},
httpClient: c.httpClient,
}
versions, err := cc.List()
versions, err := c.Client.Versions()
if err != nil {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 1
}
for _, v := range versions {
if strings.HasPrefix(v, filter) {
c.ui.Output(v)
c.UI.Output(v)
}
}
return 0
}

type client struct {
url *url.URL
httpClient *http.Client
}

func (c *client) List() ([]string, error) {
req, err := http.NewRequest(http.MethodGet, c.url.String(), nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", "tfswitch")
res, err := c.httpClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("status code error: %d %s", res.StatusCode, res.Status)
}

doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
return nil, err
}

var versions []string
doc.Find("li").Each(func(i int, s *goquery.Selection) {
v := strings.TrimPrefix(strings.TrimSpace(s.Text()), "terraform_")
if v != "../" {
versions = append(versions, v)
}
})
return versions, nil
}

func (c *remoteListCommand) Synopsis() string {
func (c *RemoteListCommand) Synopsis() string {
return "display available terraform versions in remote. (https://releases.hashicorp.com/terraform/)"
}
35 changes: 0 additions & 35 deletions internal/command/remote-list_test.go

This file was deleted.

53 changes: 14 additions & 39 deletions internal/command/use.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,26 @@
package command

import (
"context"
"fmt"
"os"
"path/filepath"

goversion "github.com/hashicorp/go-version"
install "github.com/hashicorp/hc-install"
"github.com/hashicorp/hc-install/product"
"github.com/hashicorp/hc-install/releases"
"github.com/hashicorp/hc-install/src"
"github.com/cappyzawa/tfswitch/v2/internal/repository"
"github.com/mitchellh/cli"
)

const (
tfPATH = "/usr/local/bin/terraform"
)

// useCommand describes "version" command
type useCommand struct {
ui *cli.ColoredUi
dataHome string
// UseCommand describes "version" command
type UseCommand struct {
UI *cli.ColoredUi
DataHome string

Client repository.Client
}

func (c *useCommand) Help() string {
func (c *UseCommand) Help() string {
return `This command switches the terraform version.
In case of missing specified version is missing in local, this command install the terraform binary from https://releases.hashicorp.com/terraform/ before switching.
Expand All @@ -37,42 +33,21 @@ Examples:
`
}

func (c *useCommand) Run(args []string) int {
func (c *UseCommand) Run(args []string) int {
version := args[0]
execPATH, err := installOrExtractTerraform(c.dataHome, version)
execPATH, err := c.Client.Install(c.DataHome, version)
if err != nil {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 1
}
if err := updateSymlink(execPATH, tfPATH); err != nil {
c.ui.Error(err.Error())
c.UI.Error(err.Error())
return 2
}
c.ui.Output(fmt.Sprintf("Switched terraform version to %s", version))
c.UI.Output(fmt.Sprintf("Switched terraform version to %s", version))
return 0
}

func installOrExtractTerraform(dataHome string, version string) (string, error) {
// e.g., tfDataPATH = $HOME/.local/share/tfswitch/0.14.4
tfDataPATH := filepath.Join(dataHome, "tfswitch", version)
if err := os.MkdirAll(tfDataPATH, 0755); err != nil {
return "", err
}
installer := install.NewInstaller()
tfVer := goversion.Must(goversion.NewVersion(version))
execPATH, err := installer.Ensure(context.Background(), []src.Source{
&releases.ExactVersion{
Product: product.Terraform,
Version: tfVer,
InstallDir: tfDataPATH,
},
})
if err != nil {
return "", err
}
return execPATH, nil
}

func updateSymlink(oldname, newname string) error {
if _, err := os.Lstat(newname); err == nil {
if err := os.Remove(newname); err != nil {
Expand All @@ -85,6 +60,6 @@ func updateSymlink(oldname, newname string) error {
return nil
}

func (c *useCommand) Synopsis() string {
func (c *UseCommand) Synopsis() string {
return "use specified terraform version."
}

0 comments on commit 5477b25

Please sign in to comment.