diff --git a/src/cli.ts b/src/cli.ts index 21f7964..487d47e 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,13 +1,13 @@ import * as path from 'path'; import * as fs from 'fs'; import * as os from 'os'; -import { spawnSync } from 'child_process'; import { Command } from 'commander'; import { getPlatformInfo } from './core/platform'; import { getMatchingAsset } from './core/matcher'; import { findBinary } from './core/finder'; import { fetchLatestRelease, fetchLatestReleaseRaw, downloadAsset } from './core/downloader'; import { extractAsset } from './core/extractor'; +import { installSystemPackage } from './core/installer'; interface CliOptions { appName?: string; @@ -58,31 +58,6 @@ function getInstallDir(installPath?: string): string { return '/usr/local/bin'; } -function installSystemPackage(downloadPath: string): void { - const fileName = path.basename(downloadPath).toLowerCase(); - - const command: { binary: string; args: string[] } | undefined = fileName.endsWith('.deb') - ? { binary: 'dpkg', args: ['-i', downloadPath] } - : fileName.endsWith('.pkg') - ? { binary: 'installer', args: ['-pkg', downloadPath, '-target', '/'] } - : fileName.endsWith('.rpm') - ? { binary: 'rpm', args: ['-i', downloadPath] } - : undefined; - - if (!command) { - throw new Error(`Unsupported package type: ${fileName}`); - } - - const isRoot = process.getuid && process.getuid() === 0; - const commandToRun = isRoot ? command.binary : 'sudo'; - const argsToRun = isRoot ? command.args : [command.binary, ...command.args]; - - const result = spawnSync(commandToRun, argsToRun, { stdio: 'inherit' }); - if (result.status !== 0) { - throw new Error(`Failed to install package using ${commandToRun} ${argsToRun.join(' ')}.`); - } -} - async function run() { let tempDir: string | undefined; const program = new Command(); diff --git a/src/core/installer.ts b/src/core/installer.ts new file mode 100644 index 0000000..3fe28e1 --- /dev/null +++ b/src/core/installer.ts @@ -0,0 +1,27 @@ +import * as path from 'path'; +import { spawnSync } from 'child_process'; + +export function installSystemPackage(downloadPath: string): void { + const fileName = path.basename(downloadPath).toLowerCase(); + + const command: { binary: string; args: string[] } | undefined = fileName.endsWith('.deb') + ? { binary: 'dpkg', args: ['-i', downloadPath] } + : fileName.endsWith('.pkg') + ? { binary: 'installer', args: ['-pkg', downloadPath, '-target', '/'] } + : fileName.endsWith('.rpm') + ? { binary: 'rpm', args: ['-i', downloadPath] } + : undefined; + + if (!command) { + throw new Error(`Unsupported package type: ${fileName}`); + } + + const isRoot = process.getuid && process.getuid() === 0; + const commandToRun = isRoot ? command.binary : 'sudo'; + const argsToRun = isRoot ? command.args : [command.binary, ...command.args]; + + const result = spawnSync(commandToRun, argsToRun, { stdio: 'inherit' }); + if (result.status !== 0) { + throw new Error(`Failed to install package using ${commandToRun} ${argsToRun.join(' ')}.`); + } +} diff --git a/src/index.ts b/src/index.ts index ad86422..e338ec1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,53 +7,35 @@ import { getPlatformInfo } from './core/platform'; import { getMatchingAsset } from './core/matcher'; import { findBinary } from './core/finder'; import { fetchLatestRelease } from './core/downloader'; - -function installSystemPackage(downloadPath: string): void { - const fileName = path.basename(downloadPath).toLowerCase(); - - const command: { binary: string; args: string[] } | undefined = fileName.endsWith('.deb') - ? { binary: 'dpkg', args: ['-i', downloadPath] } - : fileName.endsWith('.pkg') - ? { binary: 'installer', args: ['-pkg', downloadPath, '-target', '/'] } - : fileName.endsWith('.rpm') - ? { binary: 'rpm', args: ['-i', downloadPath] } - : undefined; - - if (!command) { - throw new Error(`Unsupported package type: ${fileName}`); - } - - const isRoot = process.getuid && process.getuid() === 0; - const commandToRun = isRoot ? command.binary : 'sudo'; - const argsToRun = isRoot ? command.args : [command.binary, ...command.args]; - - const result = spawnSync(commandToRun, argsToRun, { stdio: 'inherit' }); - if (result.status !== 0) { - throw new Error(`Failed to install package using ${commandToRun} ${argsToRun.join(' ')}.`); - } -} +import { installSystemPackage } from './core/installer'; function findInstalledBinary(binaryName: string): string | undefined { - const isRegex = binaryName.startsWith('~'); - if (!isRegex) { - const whichResult = spawnSync('which', [binaryName], { encoding: 'utf8' }); - if (whichResult.status === 0) { - const resolvedPath = (whichResult.stdout || '').trim(); - if (resolvedPath) { - return resolvedPath; - } - } + let pattern: RegExp; + + if (!binaryName.startsWith('~')) { + pattern = new RegExp(`^${binaryName}$`, 'i'); + } else { + pattern = new RegExp(binaryName.substring(1), 'i'); } - const candidates = ['/usr/local/bin', '/usr/bin', '/opt/homebrew/bin', '/opt/local/bin']; - const pattern: string | RegExp = isRegex ? new RegExp(binaryName.substring(1), 'i') : binaryName; - for (const candidateDir of candidates) { - if (!fs.existsSync(candidateDir)) { + const dirs = [ + '/usr/local/bin', + '/usr/local/sbin', + '/usr/bin', + '/usr/sbin', + '/bin', + '/sbin', + path.join(process.env.HOME || '/', 'bin'), + '/opt/homebrew/bin' + ]; + + for (const d of dirs) { + if (!fs.existsSync(d)) { continue; } - const candidatePath = findBinary(candidateDir, pattern, false, () => undefined); - if (candidatePath) { - return candidatePath; + const p = findBinary(d, pattern, false, () => undefined); + if (p) { + return p; } }