diff --git a/src/ctrace/BinaryLocator.ts b/src/ctrace/BinaryLocator.ts index 48be29e..9f37ae0 100755 --- a/src/ctrace/BinaryLocator.ts +++ b/src/ctrace/BinaryLocator.ts @@ -23,6 +23,22 @@ export async function locateBinary(extensionPath: string): Promise { + for (const dir of (process.env.PATH || '').split(path.delimiter).filter(Boolean)) { + for (const name of ['ctrace', 'coretrace']) { + const candidate = path.join(dir, name); + if (await isExecutableFile(candidate)) { + return candidate; + } + } + } + return null; +} + async function isExecutableFile(filePath: string): Promise { try { const stat = await fs.promises.stat(filePath); diff --git a/src/ctrace/BinaryUpdater.ts b/src/ctrace/BinaryUpdater.ts index c75e5b8..d504665 100755 --- a/src/ctrace/BinaryUpdater.ts +++ b/src/ctrace/BinaryUpdater.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as tar from 'tar'; import { pipeline } from 'stream/promises'; import { Readable, Transform } from 'stream'; -import { locateBinary } from './BinaryLocator'; +import { locateBinary, locateBinaryOnPath } from './BinaryLocator'; const REPO_LATEST_RELEASE_URL = 'https://api.github.com/repos/CoreTrace/coretrace/releases/latest'; @@ -53,15 +53,17 @@ async function doEnsureBinary(context: vscode.ExtensionContext, output: vscode.O const FAILURE_BACKOFF = 60 * 1000; // If we have a cached binary and checked recently, avoid spamming the GitHub API. - if (downloadedBinaryPath && now - lastCheck < TWELVE_HOURS) { - return downloadedBinaryPath; + // A PATH binary counts too: platforms without a release asset (macOS) would otherwise hit the API on every scan. + const knownBinary = downloadedBinaryPath ?? await locateBinaryOnPath(); + if (knownBinary && now - lastCheck < TWELVE_HOURS) { + return knownBinary; } // When there is no cached binary, keep retrying with a short backoff. // This avoids a 12-hour lockout if the very first download fails. if (!downloadedBinaryPath && now - lastFailedCheck < FAILURE_BACKOFF) { output.appendLine('Skipping update check due to recent failure backoff.'); - return await locateBinary(context.extensionUri.fsPath); + return await locateBinaryOnPath(); } try { @@ -121,8 +123,8 @@ async function doEnsureBinary(context: vscode.ExtensionContext, output: vscode.O const cachedBin = await getExtractedBinaryPath(binDir); if (cachedBin) return cachedBin; - // Fallback to bundled - return await locateBinary(context.extensionUri.fsPath); + // Bundled was already checked at the top; last resort is a user-installed ctrace. + return await locateBinaryOnPath(); } function getAssetForPlatform(assets: any[]): { name: string; url: string } | null { diff --git a/src/ctrace/DependencyInstaller.ts b/src/ctrace/DependencyInstaller.ts index 3ee5025..c4b91fc 100644 --- a/src/ctrace/DependencyInstaller.ts +++ b/src/ctrace/DependencyInstaller.ts @@ -235,6 +235,12 @@ elif command -v zypper >/dev/null 2>&1; then elif command -v apk >/dev/null 2>&1; then echo "Detected Alpine Linux (apk)." apk add --no-cache cppcheck flawfinder build-base git cmake python3 py3-pip curl || true +elif command -v brew >/dev/null 2>&1; then + echo "Detected macOS (Homebrew)." + # Homebrew refuses to run as root, so install as the invoking user. + sudo -u "\${SUDO_USER:-$(id -un)}" brew install cppcheck flawfinder cmake python3 || true + # IKOS is only published through NASA's tap (builds LLVM deps, can take a while). + sudo -u "\${SUDO_USER:-$(id -un)}" brew install nasa-sw-vnv/core/ikos || true else echo "Warning: Unrecognized package manager. Please ensure git, g++, make, cmake, python3, and curl are installed." fi @@ -242,7 +248,8 @@ fi echo "=== [2/5] Creating CoreTrace tools directory structure... ===" USER_HOME="$CORETRACE_USER_HOME" if [ -z "$USER_HOME" ] && [ -n "$SUDO_USER" ]; then - USER_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6) + # getent does not exist on macOS; tilde expansion works everywhere. + USER_HOME=$(eval echo "~$SUDO_USER") fi if [ -z "$USER_HOME" ]; then USER_HOME="$HOME" @@ -344,7 +351,7 @@ fi # Ensure permissions TOOLS_OWNER="$CORETRACE_USER_NAME" if [ -z "$TOOLS_OWNER" ]; then TOOLS_OWNER="$SUDO_USER"; fi -if [ -n "$TOOLS_OWNER" ]; then chown -R "$TOOLS_OWNER:$TOOLS_OWNER" "$TOOLS_DIR" 2>/dev/null || true; fi +if [ -n "$TOOLS_OWNER" ]; then chown -R "$TOOLS_OWNER" "$TOOLS_DIR" 2>/dev/null || true; fi chmod -R 755 "$TOOLS_DIR" 2>/dev/null || true echo "=== All CoreTrace dependencies installed and verified successfully! ===" diff --git a/src/extension.ts b/src/extension.ts index 5103671..c141059 100755 --- a/src/extension.ts +++ b/src/extension.ts @@ -72,8 +72,11 @@ export function activate(context: vscode.ExtensionContext) { if (!p) { const extPath = context.extensionUri.fsPath; const globalStorage = context.globalStorageUri.fsPath; + const hint = process.platform === 'darwin' + ? '\nCoreTrace publishes no prebuilt macOS binary: build it from https://github.com/CoreTrace/coretrace and put `ctrace` on your PATH.' + : ''; vscode.window.showErrorMessage( - `Ctrace binary could not be found or downloaded. Checked: \n- ${globalStorage}/bin\n- ${extPath}\nSee the "Ctrace" Output channel for details.` + `Ctrace binary could not be found or downloaded. Checked: \n- ${globalStorage}/bin\n- ${extPath}\n- PATH${hint}\nSee the "Ctrace" Output channel for details.` ); } return p;