Skip to content

Commit

Permalink
Automatically install the probe-rs binaries on request
Browse files Browse the repository at this point in the history
  • Loading branch information
Yatekii committed May 11, 2024
1 parent 2d8cf18 commit e01fc2a
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 6 deletions.
21 changes: 18 additions & 3 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,34 @@
"script": "watch",
"group": "build",
"isBackground": true,
"problemMatcher": ["$esbuild-watch"]
"problemMatcher": [
"$esbuild-watch"
]
},
{
"type": "npm",
"script": "compile-web",
"problemMatcher": ["$esbuild-watch"]
"problemMatcher": [
"$esbuild-watch"
]
},
{
"type": "npm",
"script": "watch-web",
"group": "build",
"isBackground": true,
"problemMatcher": ["$ts-webpack-watch"]
"problemMatcher": [
"$ts-webpack-watch"
]
},
{
"type": "deno",
"command": "",
"problemMatcher": [
"$deno"
],
"label": "deno task: build",
"detail": "esbuild ./src/extension.ts --bundle --tsconfig=./tsconfig.json --external:vscode --format=cjs --platform=node --outfile=dist/extension.js"
}
]
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
},
"main": "./dist/extension.js",
"activationEvents": [
"onDebug"
"onDebug",
"onStartupFinished"
],
"workspaceTrust": {
"request": "never"
Expand Down
32 changes: 32 additions & 0 deletions src/domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const path = require('path');
import {promises as fs} from 'fs';

/**
* @param {string} exe executable name (without extension if on Windows)
* @return {Promise<string|null>} executable path if found
* */
async function findExecutable(executableName: string): Promise<string | null> {
const envPath = process.env.PATH || '';
const envExt = process.env.PATHEXT || '';
const pathDirs = envPath.replace(/["]+/g, '').split(path.delimiter).filter(Boolean);
const extensions = envExt.split(';');
const candidates = pathDirs.flatMap((d) =>
extensions.map((ext) => path.join(d, executableName + ext)),
);
try {
return await Promise.any(candidates.map(checkFileExists));
} catch (e) {
return null;
}
}

async function checkFileExists(filePath): Promise<string | null> {
if ((await fs.stat(filePath)).isFile()) {
return filePath;
}
return null;
}

export async function probeRsInstalled() {
return await findExecutable('probe-rs');
}
94 changes: 93 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
ProviderResult,
WorkspaceFolder,
} from 'vscode';
import {probeRsInstalled} from './domain';

export async function activate(context: vscode.ExtensionContext) {
const descriptorFactory = new ProbeRSDebugAdapterServerDescriptorFactory();
Expand All @@ -29,9 +30,21 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.debug.onDidReceiveDebugSessionCustomEvent(
descriptorFactory.receivedCustomEvent.bind(descriptorFactory),
),
vscode.debug.onDidTerminateDebugSession(descriptorFactory.dispose.bind(descriptorFactory)),
);

(async () => {
if (await probeRsInstalled()) {
const resp = await vscode.window.showInformationMessage(
'probe-rs seems to not be installed. Do you want to install it automatically now?',
'Install',
);

if (resp === 'Install') {
await installProbeRs();
}
}
})();

// I cannot find a way to programmatically test for when VSCode is debugging the extension, versus when a user is using the extension to debug their own code, but the following code is useful in the former situation, so I will leave it here to be commented out by extension developers when needed.
// const trackerFactory = new ProbeRsDebugAdapterTrackerFactory();
// context.subscriptions.push(
Expand Down Expand Up @@ -536,6 +549,85 @@ function startDebugServer(
});
}

/// Installs probe-rs if it is not present.
function installProbeRs() {
let windows = process.platform === 'win32';
let done = false;

vscode.window.withProgress(
{
location: vscode.ProgressLocation.Window,
cancellable: false,
title: 'Installing probe-rs ...',
},
async (progress) => {
progress.report({increment: 0});

const launchedDebugAdapter = childProcess.exec(
windows
? 'irm https://github.com/probe-rs/probe-rs/releases/download/latest/probe-rs-installer.ps1 | iex'
: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/probe-rs/probe-rs/releases/latest/download/probe-rs-installer.sh | sh",
(error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
done = true;
return;
}
console.log(`stdout: ${stdout}`);
console.log(`stderr: ${stderr}`);
},
);

const errorListener = (err: Error) => {
progress.report({
increment: 100,
message: 'Installation failed. Check the logs for more info.',
});
done = true;
};

const exitListener = (code: number | null, signal: NodeJS.Signals | null) => {
if (code === 0) {
progress.report({
increment: 100,
message: 'Installation successful.',
});
done = true;
} else if (signal) {
progress.report({
increment: 100,
message: 'Installation aborted.',
});
done = true;
} else {
progress.report({
increment: 100,
message: 'Installation failed. Check the logs for more info.',
});
done = true;
}
};

launchedDebugAdapter.on('spawn', () => {
// The error listener here is only used for failed spawn,
// so has to be removed afterwards.
launchedDebugAdapter.removeListener('error', errorListener);
});

const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

launchedDebugAdapter.on('error', errorListener);
launchedDebugAdapter.on('exit', exitListener);

while (!done) {
await delay(100);
}

progress.report({increment: 100});
},
);
}

// Get the name of the debugger executable
//
// This takes the value from configuration, if set, or
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"module": "commonjs",
"target": "es6",
"outDir": "out",
"lib": ["es6"],
"lib": ["es2021"],
"sourceMap": true,
"rootDir": "src",
"strict": true /* enable all strict type-checking options */,
Expand Down

0 comments on commit e01fc2a

Please sign in to comment.