Skip to content

Commit

Permalink
- added pruning of old versions
Browse files Browse the repository at this point in the history
- made sure that the order of the recent files are kept
- renamed functions and variables to less generic
  • Loading branch information
MatrixCrawler committed May 27, 2024
1 parent 9a1f18b commit 561ead2
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 53 deletions.
6 changes: 3 additions & 3 deletions lib/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ func GetDefaultBin() string {
const (
DefaultMirror = "https://releases.hashicorp.com/terraform"
DefaultLatest = ""
distTerraform = "terraform"
distTofu = "tofu"
distributionTerraform = "terraform"
distributionOpenTofu = "opentofu"
installFile = "terraform"
InstallDir = ".terraform.versions"
pubKeySuffix = ".asc"
recentFile = "RECENT"
TerraformPrefix = "terraform_"
tfDarwinArm64StartVersion = "1.0.2"
VersionPrefix = "terraform_"
)
22 changes: 11 additions & 11 deletions lib/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
}

/* check if selected version already downloaded */
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, VersionPrefix+tfversion))
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, TerraformPrefix+tfversion))
fileExist := CheckFileExist(installFileVersionPath)

/* if selected version already exist, */
Expand All @@ -90,7 +90,7 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
/* set symlink to desired version */
CreateSymlink(installFileVersionPath, binPath)
logger.Infof("Switched terraform to version %q", tfversion)
addRecent(tfversion, installPath, distTerraform) //add to recent file for faster lookup
addRecent(tfversion, installPath, distributionTerraform) //add to recent file for faster lookup
return
}

Expand All @@ -102,7 +102,7 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str

/* if selected version already exist, */
/* proceed to download it from the hashicorp release page */
zipFile, errDownload := DownloadFromURL(installLocation, mirrorURL, tfversion, VersionPrefix, goos, goarch)
zipFile, errDownload := DownloadFromURL(installLocation, mirrorURL, tfversion, TerraformPrefix, goos, goarch)

/* If unable to download file from url, exit(1) immediately */
if errDownload != nil {
Expand Down Expand Up @@ -134,11 +134,11 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
/* set symlink to desired version */
CreateSymlink(installFileVersionPath, binPath)
logger.Infof("Switched terraform to version %q", tfversion)
addRecent(tfversion, installPath, distTerraform) //add to recent file for faster lookup
addRecent(tfversion, installPath, distributionTerraform) //add to recent file for faster lookup
return
}

// ConvertExecutableExt : convert excutable with local OS extension
// ConvertExecutableExt : convert executable with local OS extension
func ConvertExecutableExt(fpath string) string {
switch runtime.GOOS {
case "windows":
Expand Down Expand Up @@ -221,12 +221,12 @@ func InstallVersion(dryRun bool, version, customBinaryPath, installPath, mirrorU

//check to see if the requested version has been downloaded before
installLocation := GetInstallLocation(installPath)
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, VersionPrefix+requestedVersion))
installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, TerraformPrefix+requestedVersion))
recentDownloadFile := CheckFileExist(installFileVersionPath)
if recentDownloadFile {
ChangeSymlink(installFileVersionPath, customBinaryPath)
logger.Infof("Switched terraform to version %q", requestedVersion)
addRecent(requestedVersion, installPath, distTerraform) //add to recent file for faster lookup
addRecent(requestedVersion, installPath, distributionTerraform) //add to recent file for faster lookup
return
}

Expand All @@ -253,10 +253,10 @@ func InstallVersion(dryRun bool, version, customBinaryPath, installPath, mirrorU
/* listAll = true - all versions including beta and rc will be displayed */
/* listAll = false - only official stable release are displayed */
func InstallOption(listAll, dryRun bool, customBinaryPath, installPath string, mirrorURL string) {
tflist, _ := getTFList(mirrorURL, listAll) // Get list of versions
recentVersions, _ := getRecentVersions(installPath, distTerraform) // Get recent versions from RECENT file
tflist = append(recentVersions, tflist...) // Append recent versions to the top of the list
tflist = removeDuplicateVersions(tflist) // Remove duplicate version
tflist, _ := getTFList(mirrorURL, listAll) // Get list of versions
recentVersions, _ := getRecentVersions(installPath, distributionTerraform) // Get recent versions from RECENT file
tflist = append(recentVersions, tflist...) // Append recent versions to the top of the list
tflist = removeDuplicateVersions(tflist) // Remove duplicate version

if len(tflist) == 0 {
logger.Fatalf("Terraform version list is empty: %s", mirrorURL)
Expand Down
2 changes: 1 addition & 1 deletion lib/param_parsing/parameters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func TestGetParameters_dry_run_wont_download_anything(t *testing.T) {
os.Args = []string{"cmd", "--chdir=" + expected, "--bin=/tmp", "--dry-run"}
params := GetParameters()
installLocation := lib.GetInstallLocation(params.InstallPath)
installFileVersionPath := lib.ConvertExecutableExt(filepath.Join(installLocation, lib.VersionPrefix+params.Version))
installFileVersionPath := lib.ConvertExecutableExt(filepath.Join(installLocation, lib.TerraformPrefix+params.Version))
// Make sure the file tfswitch WOULD download is absent
_ = os.Remove(installFileVersionPath)
lib.InstallVersion(params.DryRun, params.Version, params.CustomBinaryPath, params.InstallPath, params.MirrorURL)
Expand Down
81 changes: 62 additions & 19 deletions lib/recent.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (

type RecentFiles struct {
Terraform []string `json:"terraform"`
Tofu []string `json:"tofu"`
OpenTofu []string `json:"openTofu"`
}

func addRecent(requestedVersion string, installPath string, dist string) {
func addRecent(requestedVersion string, installPath string, distribution string) {
if !validVersionFormat(requestedVersion) {
logger.Errorf("The version %q is not a valid version string and won't be stored", requestedVersion)
return
Expand All @@ -21,48 +21,91 @@ func addRecent(requestedVersion string, installPath string, dist string) {
recentFilePath := filepath.Join(installLocation, recentFile)
var recentFileData RecentFiles
if CheckFileExist(recentFilePath) {
unmarshal(recentFilePath, &recentFileData)
unmarshalRecentFileData(recentFilePath, &recentFileData)
}

prependRecentVersionToList(requestedVersion, installPath, distribution, &recentFileData)
var sliceToCheck []string
if dist == distTerraform {
if distribution == distributionTerraform {
sliceToCheck = recentFileData.Terraform
} else if dist == distTofu {
sliceToCheck = recentFileData.Tofu
} else if distribution == distributionOpenTofu {
sliceToCheck = recentFileData.OpenTofu
}
for _, v := range sliceToCheck {
if v == requestedVersion {
// entry already exists. Nothing to do
// entry already exists. Nothing to add but move it first
return
}
}
if dist == distTerraform {
if distribution == distributionTerraform {
recentFileData.Terraform = append(recentFileData.Terraform, requestedVersion)
} else if dist == distTofu {
recentFileData.Tofu = append(recentFileData.Tofu, requestedVersion)
} else if distribution == distributionOpenTofu {
recentFileData.OpenTofu = append(recentFileData.OpenTofu, requestedVersion)
}
saveRecentFile(recentFileData, recentFilePath)
}

func prependRecentVersionToList(version, installPath, distribution string, r *RecentFiles) {
var sliceToCheck []string
if distribution == distributionTerraform {
sliceToCheck = r.Terraform
} else if distribution == distributionOpenTofu {
sliceToCheck = r.OpenTofu
}
for versionIndex, versionValue := range sliceToCheck {
if versionValue == version {
sliceToCheck = append(sliceToCheck[:versionIndex], sliceToCheck[versionIndex+1:]...)
}
}
sliceToCheck = append([]string{version}, sliceToCheck...)

//TODO delete files that are falling of the first three slice elements
//if len(sliceToCheck) > 3 {
// deleteDownloadedBinaries(installPath, distribution, sliceToCheck[3:])
// sliceToCheck = sliceToCheck[0:2]
//}

if distribution == distributionTerraform {
r.Terraform = sliceToCheck
} else if distribution == distributionOpenTofu {
r.OpenTofu = sliceToCheck
}

}

func deleteDownloadedBinaries(installPath, distribution string, versions []string) {
installLocation := GetInstallLocation(installPath)
for _, versionToDelete := range versions {
var fileToDelete string
if distribution == distributionTerraform {
fileToDelete = ConvertExecutableExt(TerraformPrefix + versionToDelete)
}
filePathToDelete := filepath.Join(installLocation, fileToDelete)
logger.Debugf("Deleting obsolete binary %v", filePathToDelete)
_ = os.Remove(filePathToDelete)
}
saveFile(recentFileData, recentFilePath)
}

func getRecentVersions(installPath string, dist string) ([]string, error) {
installLocation := GetInstallLocation(installPath)
recentFilePath := filepath.Join(installLocation, recentFile)
var recentFileData RecentFiles
unmarshal(recentFilePath, &recentFileData)
if dist == distTerraform {
unmarshalRecentFileData(recentFilePath, &recentFileData)
if dist == distributionTerraform {
return recentFileData.Terraform, nil
} else if dist == distTofu {
return recentFileData.Tofu, nil
} else if dist == distributionOpenTofu {
return recentFileData.OpenTofu, nil
}
return nil, nil
}

func unmarshal(recentFilePath string, recentFileData *RecentFiles) {
func unmarshalRecentFileData(recentFilePath string, recentFileData *RecentFiles) {
recentFileContent, err := os.ReadFile(recentFilePath)
if err != nil {
logger.Errorf("Could not open recent versions file %q", recentFilePath)
}
if string(recentFileContent[0:1]) != "{" {
convertData(recentFileContent, recentFileData)
convertOldRecentFile(recentFileContent, recentFileData)
} else {
err = json.Unmarshal(recentFileContent, &recentFileData)
if err != nil {
Expand All @@ -71,7 +114,7 @@ func unmarshal(recentFilePath string, recentFileData *RecentFiles) {
}
}

func convertData(content []byte, recentFileData *RecentFiles) {
func convertOldRecentFile(content []byte, recentFileData *RecentFiles) {
lines := strings.Split(string(content), "\n")
for _, s := range lines {
if s != "" {
Expand All @@ -80,7 +123,7 @@ func convertData(content []byte, recentFileData *RecentFiles) {
}
}

func saveFile(data RecentFiles, path string) {
func saveRecentFile(data RecentFiles, path string) {
bytes, err := json.Marshal(data)
if err != nil {
logger.Errorf("Could not marshal data to JSON: %v", err)
Expand Down
70 changes: 52 additions & 18 deletions lib/recent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,55 +14,55 @@ func Test_convertData(t *testing.T) {
}

var recentFileData RecentFiles
convertData(recentFileContent, &recentFileData)
convertOldRecentFile(recentFileContent, &recentFileData)
assert.Equal(t, 3, len(recentFileData.Terraform))
assert.Equal(t, 0, len(recentFileData.OpenTofu))
assert.Equal(t, "1.5.6", recentFileData.Terraform[0])
assert.Equal(t, "0.13.0-rc1", recentFileData.Terraform[1])
assert.Equal(t, "1.0.11", recentFileData.Terraform[2])
assert.Equal(t, 3, len(recentFileData.Terraform))
assert.Equal(t, 0, len(recentFileData.Tofu))
}

func Test_saveFile(t *testing.T) {
var recentFileData = RecentFiles{
Terraform: []string{"1.2.3", "4.5.6"},
Tofu: []string{"6.6.6"},
OpenTofu: []string{"6.6.6"},
}
temp, err := os.MkdirTemp("", "recent-test")
defer func(path string) {
_ = os.RemoveAll(path)
}(temp)
if err != nil {
t.Errorf("Could not create temporary directory")
}
defer func(path string) {
_ = os.RemoveAll(temp)
}(temp)
pathToTempFile := filepath.Join(temp, "recent.json")
saveFile(recentFileData, pathToTempFile)
saveRecentFile(recentFileData, pathToTempFile)

content, err := os.ReadFile(pathToTempFile)
if err != nil {
t.Errorf("Could not read converted file %v", pathToTempFile)
}
assert.Equal(t, "{\"terraform\":[\"1.2.3\",\"4.5.6\"],\"tofu\":[\"6.6.6\"]}", string(content))
assert.Equal(t, "{\"terraform\":[\"1.2.3\",\"4.5.6\"],\"openTofu\":[\"6.6.6\"]}", string(content))
}

func Test_getRecentVersionsGenericForTerraform(t *testing.T) {
func Test_getRecentVersionsForTerraform(t *testing.T) {
logger = InitLogger("DEBUG")
strings, err := getRecentVersions("../test-data/recent/recent_as_json/", distTerraform)
strings, err := getRecentVersions("../test-data/recent/recent_as_json/", distributionTerraform)
if err != nil {
t.Error("Unable to get versions from recent file")
}
assert.Equal(t, []string{"1.2.3", "4.5.6"}, strings)
}

func Test_getRecentVersionsGenericForTofu(t *testing.T) {
func Test_getRecentVersionsForOpenTofu(t *testing.T) {
logger = InitLogger("DEBUG")
strings, err := getRecentVersions("../test-data/recent/recent_as_json", distTofu)
strings, err := getRecentVersions("../test-data/recent/recent_as_json", distributionOpenTofu)
if err != nil {
t.Error("Unable to get versions from recent file")
}
assert.Equal(t, []string{"6.6.6"}, strings)
}

func Test_addRecentGenericForTerraform(t *testing.T) {
func Test_addRecent(t *testing.T) {
logger = InitLogger("DEBUG")
temp, err := os.MkdirTemp("", "recent-test")
defer func(path string) {
Expand All @@ -71,19 +71,53 @@ func Test_addRecentGenericForTerraform(t *testing.T) {
if err != nil {
t.Errorf("Could not create temporary directory")
}
addRecent("3.7.0", temp, distTerraform)
addRecent("3.7.0", temp, distributionTerraform)
addRecent("3.7.1", temp, distributionTerraform)
addRecent("3.7.2", temp, distributionTerraform)
bytes, err := os.ReadFile(filepath.Join(temp, ".terraform.versions", "RECENT"))
if err != nil {
t.Error("Could not open file")
t.Error(err)
}
assert.Equal(t, "{\"terraform\":[\"3.7.0\"],\"tofu\":null}", string(bytes))
assert.Equal(t, "{\"terraform\":[\"3.7.0\",\"3.7.1\",\"3.7.2\"],\"openTofu\":null}", string(bytes))
addRecent("3.7.2", temp, distributionTerraform)
assert.Equal(t, "{\"terraform\":[\"3.7.2\",\"3.7.0\",\"3.7.1\"],\"openTofu\":null}", string(bytes))

addRecent("1.1.1", temp, distTofu)
addRecent("1.1.1", temp, distributionOpenTofu)
bytes, err = os.ReadFile(filepath.Join(temp, ".terraform.versions", "RECENT"))
if err != nil {
t.Error("Could not open file")
t.Error(err)
}
assert.Equal(t, "{\"terraform\":[\"3.7.0\"],\"tofu\":[\"1.1.1\"]}", string(bytes))
assert.Equal(t, "{\"terraform\":[\"3.7.2\",\"3.7.0\",\"3.7.1\"],\"openTofu\":[\"1.1.1\"]}", string(bytes))
}

func Test_prependExistingVersionIsMovingToTop(t *testing.T) {
var recentFileData = RecentFiles{
Terraform: []string{"1.2.3", "4.5.6", "7.7.7"},
OpenTofu: []string{"6.6.6"},
}
prependRecentVersionToList("7.7.7", "", distributionTerraform, &recentFileData)
assert.Equal(t, 3, len(recentFileData.Terraform))
assert.Equal(t, "7.7.7", recentFileData.Terraform[0])
assert.Equal(t, "1.2.3", recentFileData.Terraform[1])
assert.Equal(t, "4.5.6", recentFileData.Terraform[2])

prependRecentVersionToList("1.2.3", "", distributionTerraform, &recentFileData)
assert.Equal(t, 3, len(recentFileData.Terraform))
assert.Equal(t, "1.2.3", recentFileData.Terraform[0])
assert.Equal(t, "7.7.7", recentFileData.Terraform[1])
assert.Equal(t, "4.5.6", recentFileData.Terraform[2])
}

func Test_prependNewVersion(t *testing.T) {
var recentFileData = RecentFiles{
Terraform: []string{"1.2.3", "4.5.6"},
OpenTofu: []string{"6.6.6"},
}
prependRecentVersionToList("7.7.7", "", distributionTerraform, &recentFileData)
assert.Equal(t, 3, len(recentFileData.Terraform))
assert.Equal(t, "7.7.7", recentFileData.Terraform[0])
assert.Equal(t, "1.2.3", recentFileData.Terraform[1])
assert.Equal(t, "4.5.6", recentFileData.Terraform[2])
}
2 changes: 1 addition & 1 deletion test-data/recent/recent_as_json/.terraform.versions/RECENT
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"terraform":["1.2.3","4.5.6"],"tofu":["6.6.6"]}
{"terraform":["1.2.3","4.5.6"],"openTofu":["6.6.6"]}

0 comments on commit 561ead2

Please sign in to comment.