UNPKG

@byu-oit/tfvm

Version:

A CLI app for easily switching between Terraform versions

111 lines (102 loc) 5.26 kB
import chalk from 'chalk' import deleteExecutable from '../util/deleteExecutable.js' import fs from 'node:fs/promises' import { versionRegEx, LOWEST_OTF_VERSION } from '../util/constants.js' import getInstalledVersions from '../util/getInstalledVersions.js' import download from '../util/download.js' import unzipFile from '../util/unzipFile.js' import getErrorMessage from '../util/errorChecker.js' import getTerraformVersion from '../util/tfVersion.js' import getLatest from '../util/getLatest.js' import { logger } from '../util/logger.js' import getSettings from '../util/getSettings.js' import { getOS, Mac } from '../util/tfvmOS.js' import { compare } from 'compare-versions' import * as semver from 'semver' const os = getOS() const LAST_TF_VERSION_WITHOUT_ARM = '1.0.1' async function install (versionNum) { try { const settings = await getSettings() const installVersion = 'v' + versionNum const openTofuCheck = settings.useOpenTofu && semver.gte(versionNum, LOWEST_OTF_VERSION) if (!versionRegEx.test(installVersion) && versionNum !== 'latest') { logger.warn(`invalid version attempted to install with version ${installVersion}`) console.log(chalk.red.bold('Invalid version syntax.')) if (settings.useOpenTofu) { console.log(chalk.white.bold('Version should be formatted as \'vX.X.X\'\nGet a list of all current ' + 'opentofu versions here: https://github.com/opentofu/opentofu/releases')) } else { console.log(chalk.white.bold('Version should be formatted as \'vX.X.X\'\nGet a list of all current ' + 'terraform versions here: https://releases.hashicorp.com/terraform/')) } } else if (versionNum === 'latest') { const installedVersions = await getInstalledVersions() const latest = await getLatest() const currentVersion = await getTerraformVersion() if (latest) { const versionLatest = 'v' + latest if (installedVersions.includes(versionLatest) && currentVersion !== versionLatest) { console.log(chalk.bold.cyan(`The latest ${openTofuCheck ? 'opentofu' : 'terraform'} version is ${latest} and is ` + `already installed on your computer. Run 'tfvm use ${latest}' to use.`)) } else if (installedVersions.includes(versionLatest) && currentVersion === versionLatest) { const currentVersion = await getTerraformVersion() console.log(chalk.bold.cyan(`The latest ${openTofuCheck ? 'opentofu' : 'terraform'} version is ${currentVersion} and ` + 'is already installed and in use on your computer.')) } else { await installFromWeb(latest) } } } else { const installedVersions = await getInstalledVersions() if (installedVersions.includes(installVersion)) { console.log(chalk.white.bold(`${openTofuCheck ? 'OpenTofu' : 'Terraform'} version ${installVersion} is already installed.`)) } else { await installFromWeb(versionNum) } } } catch (error) { logger.fatal(error, `Fatal error when running "install" command where versionNum=${versionNum}: `) getErrorMessage(error) } } export default install export async function installFromWeb (versionNum, printMessage = true) { const settings = await getSettings() const openTofuCheck = settings.useOpenTofu && semver.gte(versionNum, LOWEST_OTF_VERSION) const openTofuCheckLessThan = settings.useOpenTofu && semver.lt(versionNum, LOWEST_OTF_VERSION) if (openTofuCheckLessThan) { await deleteExecutable(false) } else if (openTofuCheck) { await deleteExecutable(true) } let url let zipPath let newVersionDir let arch = os.getArchitecture() // Only newer terraform versions include a release for ARM (Apple Silicon) hardware, but their chips *can* // run the amd64 ones, it just isn't ideal. If the user requests to download a terraform version that doesn't // have an arm release (and they are on an Arm Mac), then just download the amd64 one instead. if (os instanceof Mac && arch === 'arm64' && compare(versionNum, LAST_TF_VERSION_WITHOUT_ARM, '<=')) { arch = 'amd64' console.log(chalk.bold.yellow(`Warning: There is no available ARM release of Terraform for version ${versionNum}. Installing the amd64 version instead (should run without issue via Rosetta)...`)) } if (openTofuCheck) { zipPath = os.getPath(os.getOtfVersionsDir(), `v${versionNum}.zip`) newVersionDir = os.getPath(os.getOtfVersionsDir(), 'v' + versionNum) url = `https://github.com/opentofu/opentofu/releases/download/v${versionNum}/tofu_${versionNum}_${os.getOSName()}_${arch}.zip` } else { zipPath = os.getPath(os.getTfVersionsDir(), `v${versionNum}.zip`) newVersionDir = os.getPath(os.getTfVersionsDir(), 'v' + versionNum) url = `https://releases.hashicorp.com/terraform/${versionNum}/terraform_${versionNum}_${os.getOSName()}_${arch}.zip` } await download(url, zipPath, versionNum) await fs.mkdir(newVersionDir) await unzipFile(zipPath, newVersionDir) await fs.unlink(zipPath) await os.prepareExecutable(versionNum) if (printMessage) { console.log(chalk.bold.cyan(`Installation complete. If you want to use this version, type\n\ntfvm use ${versionNum}`)) } }