@controlplane/cli
Version:
Control Plane Corporation CLI
204 lines • 7.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HOMEBREW_FORMULA = exports.PACKAGE_NAME = void 0;
exports.detectInstallMethod = detectInstallMethod;
exports.detectPackageManager = detectPackageManager;
exports.packageManagerUpgradeCommand = packageManagerUpgradeCommand;
exports.homebrewUpgradeCommand = homebrewUpgradeCommand;
exports.homebrewRefreshCommand = homebrewRefreshCommand;
exports.renderCommand = renderCommand;
exports.probeInstall = probeInstall;
const fs = require("fs");
const io_1 = require("../util/io");
const version_1 = require("../util/version");
Object.defineProperty(exports, "PACKAGE_NAME", { enumerable: true, get: function () { return version_1.PACKAGE_NAME; } });
// ANCHOR - Constants
/** Path segments that only appear when Homebrew owns the executable. */
const HOMEBREW_PATH_MARKERS = ['/Cellar/', '/Caskroom/'];
/** Path segments that mark a package manager's GLOBAL install root (npm/nvm/n/fnm/volta/asdf/pnpm/yarn, unix and Windows). */
const GLOBAL_INSTALL_MARKERS = [
'/lib/node_modules/',
'/appdata/roaming/npm/node_modules/',
'/program files/nodejs/node_modules/',
'/roaming/nvm/',
'/pnpm/global/',
'/.config/yarn/global/',
'/yarn/data/global/',
'/.yarn/',
];
/** The Homebrew formula name for the CLI. */
exports.HOMEBREW_FORMULA = 'cpln';
// SECTION - Functions
/**
* Infers how the running `cpln` was installed from a set of environment inputs.
*
* Precedence matters: a Homebrew install is itself a packaged binary, so it must
* be checked before the generic packaged-binary case; a source checkout is the
* only build without a baked version.
*
* @param {InstallProbe} probe - The environment inputs describing the running process.
* @returns {InstallMethod} The inferred install method.
*/
function detectInstallMethod(probe) {
// A source checkout runs under node and carries no baked version
if (!probe.isPackaged && probe.npmVersion === 'dev') {
return 'source';
}
// Homebrew ships cpln as a packaged binary inside its Cellar/Caskroom
if (probe.isPackaged && isHomebrewOwned(probe.execPath, probe.env)) {
return 'homebrew';
}
// Any other packaged single-binary was downloaded directly
if (probe.isPackaged) {
return 'binary';
}
// A copy in a project's node_modules or the npx cache is a project dependency;
// a global upgrade would leave the copy actually in use untouched
if (isProjectLocal(probe.scriptPath)) {
return 'local';
}
// Running under node with a real version means it was installed from a registry
return 'npm';
}
/**
* Determines whether the executable path is owned by Homebrew.
*
* @param {string} execPath - The real path of the running executable.
* @param {NodeJS.ProcessEnv} env - The process environment, consulted for HOMEBREW_* hints.
* @returns {boolean} True when the path resolves inside a Homebrew Cellar/Caskroom or prefix.
*/
function isHomebrewOwned(execPath, env) {
// The Cellar/Caskroom segment is the precise, prefix-independent signal
if (HOMEBREW_PATH_MARKERS.some((marker) => execPath.includes(marker))) {
return true;
}
// Honor an explicit cellar location exported by a Homebrew shell
const cellar = env.HOMEBREW_CELLAR;
if (cellar && execPath.startsWith(cellar)) {
return true;
}
return false;
}
/**
* Determines whether the running CLI is a project-local dependency rather than a
* global install: in the npx cache, or in a node_modules that is not any package
* manager's global root.
*
* @param {string} scriptPath - The resolved main module path of the running CLI.
* @returns {boolean} True when the CLI in use is not a global install.
*/
function isProjectLocal(scriptPath) {
const normalized = normalizePath(scriptPath);
// npx runs packages out of its own cache directory
if (normalized.includes('/_npx/')) {
return true;
}
if (GLOBAL_INSTALL_MARKERS.some((marker) => normalized.includes(marker))) {
return false;
}
return normalized.includes('/node_modules/');
}
/**
* Normalizes a path for marker matching: forward slashes, lowercase.
*
* @param {string} filePath - The path to normalize.
* @returns {string} The normalized path.
*/
function normalizePath(filePath) {
return (0, io_1.posixPath)(filePath).toLowerCase();
}
/**
* Resolves which package manager owns a global npm-family install from the module path.
*
* @param {string} scriptPath - The resolved main module path of the running CLI.
* @returns {PackageManager} The detected package manager, defaulting to npm.
*/
function detectPackageManager(scriptPath) {
const normalized = normalizePath(scriptPath);
// pnpm nests global packages under a .pnpm store or a pnpm global directory
if (normalized.includes('/.pnpm/') || normalized.includes('/pnpm/global/')) {
return 'pnpm';
}
// yarn keeps global packages under its own config/data directory
// (~/.config/yarn on unix, %LOCALAPPDATA%/Yarn/Data on Windows)
if (normalized.includes('/.config/yarn/') || normalized.includes('/.yarn/') || normalized.includes('/yarn/data/global/')) {
return 'yarn';
}
return 'npm';
}
/**
* Builds the upgrade command for a given package manager targeting the latest release.
*
* @param {PackageManager} manager - The package manager to build the command for.
* @returns {RunnableCommand} The program and arguments that upgrade the CLI globally.
*/
function packageManagerUpgradeCommand(manager) {
const target = `${version_1.PACKAGE_NAME}@latest`;
switch (manager) {
case 'pnpm':
return { program: 'pnpm', args: ['add', '-g', target] };
case 'yarn':
return { program: 'yarn', args: ['global', 'add', target] };
default:
return { program: 'npm', args: ['install', '-g', target] };
}
}
/**
* Builds the Homebrew upgrade command for the CLI formula.
*
* @returns {RunnableCommand} The `brew upgrade cpln` command.
*/
function homebrewUpgradeCommand() {
return { program: 'brew', args: ['upgrade', exports.HOMEBREW_FORMULA] };
}
/**
* Builds the Homebrew tap-refresh command. Running this before an upgrade prevents
* a stale local tap from reporting "already up to date" against an old formula.
*
* @returns {RunnableCommand} The `brew update` command.
*/
function homebrewRefreshCommand() {
return { program: 'brew', args: ['update'] };
}
/**
* Renders a runnable command back into a copy-pasteable shell string.
*
* @param {RunnableCommand} command - The command to render.
* @returns {string} The command as a single shell-ready line.
*/
function renderCommand(command) {
return [command.program, ...command.args].join(' ');
}
/**
* Builds an InstallProbe from the live process, resolving symlinks so a Homebrew
* bin symlink is seen as its underlying Cellar path.
*
* @returns {InstallProbe} The environment inputs describing the running process.
*/
function probeInstall() {
var _a, _b;
return {
execPath: safeRealpath(process.execPath),
scriptPath: (_b = (_a = require.main) === null || _a === void 0 ? void 0 : _a.filename) !== null && _b !== void 0 ? _b : '',
isPackaged: Boolean(process.pkg) || 'pkg' in process.versions,
npmVersion: version_1.About.npm,
env: process.env,
};
}
/**
* Resolves a path to its canonical location, falling back to the input when it
* cannot be resolved (e.g., the file no longer exists).
*
* @param {string} filePath - The path to resolve.
* @returns {string} The real path, or the original path on failure.
*/
function safeRealpath(filePath) {
try {
return fs.realpathSync(filePath);
}
catch (_a) {
return filePath;
}
}
// !SECTION
//# sourceMappingURL=install-method.js.map