UNPKG

@nu-art/commando

Version:

Shell command execution framework with interactive sessions, CLI parameter resolution, and plugin system for building and executing shell scripts programmatically

157 lines (156 loc) 6.1 kB
/* * commando provides shell command execution framework with interactive sessions and plugin system * * Copyright (C) 2020 Adam van der Kruk aka TacB0sS * * 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. */ import * as fs from 'fs'; import { promises as _fs } from 'fs'; import * as path from 'path'; import { Logger, LogLevel } from '@nu-art/ts-common'; const CONST__FILE_NVMRC = '.nvmrc'; /** * NVM (Node Version Manager) service for managing Node.js installations. * * Handles installation, version management, and configuration of NVM. * Works with Commando_NVM plugin to execute NVM commands. * * **Features**: * - Install/uninstall NVM * - Configure shell RC files (.bashrc, .zshrc) * - Version management * - Integration with .nvmrc files */ export class Cli_NVM extends Logger { _expectedVersion = '0.39.7'; _homeEnvVar = '$NVM_DIR'; constructor() { super(); this.setMinLevel(LogLevel.Verbose); } get homeEnvVar() { return this._homeEnvVar; } set homeEnvVar(value) { this._homeEnvVar = value; } get expectedVersion() { return this._expectedVersion; } set expectedVersion(value) { this._expectedVersion = value; } /** * Installs NVM and configures shell RC files. * * **Behavior**: * - Checks if NVM is already installed with expected version * - Uninstalls if version mismatch * - Installs NVM via Commando_NVM * - Configures .bashrc with NVM initialization (if not already present) * * * @param commando - Commando_NVM instance to use for installation * @returns This instance for method chaining */ install = async (commando) => { if (this.isInstalled()) { const version = (await commando.getVersion()).trim(); if (this._expectedVersion === version) return; await this.uninstall(); } await commando.install(this._expectedVersion); const rcFile = path.resolve(process.env['HOME'], '.bashrc'); let rcFileContent = ''; if (fs.existsSync(rcFile)) { rcFileContent = await _fs.readFile(rcFile, { encoding: 'utf8' }); // If NVM is already configured, don't add it again if (rcFileContent.includes('NVM_DIR')) return this; } // Append NVM initialization to the end of the file rcFileContent = `${rcFileContent}${rcFileContent.endsWith('\n') ? '' : '\n'}`; rcFileContent += `# generated NVM - start\n`; rcFileContent += `export NVM_DIR="$HOME/.nvm"\n`; rcFileContent += `[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm\n`; rcFileContent += `[ -s "$NVM_DIR/bash_completion" ] && \\. "$NVM_DIR/bash_completion" # This loads nvm bash_completion\n`; rcFileContent += `# generated NVM - end\n`; await _fs.writeFile(rcFile, rcFileContent, { encoding: 'utf8' }); return this; }; /** * Checks if NVM is installed. * * Verifies both environment variable and directory existence. * * @returns True if NVM is installed */ isInstalled = () => !!process.env[this._homeEnvVar] && fs.existsSync(process.env[this._homeEnvVar]); /** * Reads the required Node.js version from .nvmrc file. * * @returns Promise resolving to version string from .nvmrc * @throws Error if .nvmrc file doesn't exist */ getRequiredNode_Version = async () => { const absolutePathToNvmrcFile = path.resolve(CONST__FILE_NVMRC); if (!fs.existsSync(absolutePathToNvmrcFile)) throw new Error(`couldn't find .nvmrc file at: ${absolutePathToNvmrcFile}`); const content = await _fs.readFile(absolutePathToNvmrcFile, { encoding: 'utf-8' }); return content.trim(); }; /** * Installs required Node.js version if not already installed. * * Reads .nvmrc, checks installed versions, and installs if missing. * * @param commando - Commando_NVM instance to use * @returns True if version was installed, false if already present */ installRequiredVersionIfNeeded = async (commando) => { const requiredVersion = await this.getRequiredNode_Version(); const installedVersions = await commando.getInstalledNodeVersions(); this.logDebug('Found versions:', installedVersions); if (installedVersions.includes(requiredVersion)) return false; await this.installVersion(commando, requiredVersion); return true; }; /** * Uninstalls NVM by removing its directory. * * @returns Promise that resolves when uninstall completes */ uninstall = async () => { this.logDebug('Uninstalling NVM'); const absolutePathToNVM_Home = process.env[this._homeEnvVar]; if (!absolutePathToNVM_Home) return; fs.rmSync(absolutePathToNVM_Home, { recursive: true, force: true }); }; /** * Installs a specific Node.js version via NVM. * * @param commando - Commando_NVM instance to use * @param requiredVersion - Optional version (defaults to .nvmrc value) * @returns Promise that resolves when installation completes */ installVersion = async (commando, requiredVersion) => { requiredVersion ??= await this.getRequiredNode_Version(); this.logDebug(`Installing version: ${requiredVersion}`); return commando.installNodeVersion(requiredVersion); }; } export const NVM = new Cli_NVM();