Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lamadio/0.9 fixes #898

Merged
merged 5 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/build-tool/colcon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ import * as common from "./common";
import * as rosShell from "./ros-shell";

function makeColcon(command: string, verb: string, args: string[], category?: string): vscode.Task {
const task = rosShell.make({type: command, command, args: [verb, '--symlink-install', '--event-handlers', 'console_cohesion+', '--base-paths', extension.baseDir, `--cmake-args`, `-DCMAKE_BUILD_TYPE=RelWithDebInfo`,...args]},
let installType = '--symlink-install';
if (process.platform === "win32") {

// Use Merge Install on Windows to support adminless builds and deployment.
installType = '--merge-install';
}

const task = rosShell.make({type: command, command, args: [verb, installType, '--event-handlers', 'console_cohesion+', '--base-paths', extension.baseDir, `--cmake-args`, `-DCMAKE_BUILD_TYPE=RelWithDebInfo`,...args]},
category)
task.problemMatchers = ["$catkin-gcc"];

Expand Down
4 changes: 2 additions & 2 deletions src/debugger/configuration/resolvers/ros1/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
// Manage the status of the ROS core, starting one if not present
// The ROS core will continue to run until the VSCode window is closed
if (await rosApi.getCoreStatus() == false) {
console.log("ROS Core is not active, attempting to start automatically");
extension.outputChannel.appendLine("ROS Core is not active, attempting to start automatically");
rosApi.startCore();

// Wait for the core to start up to a timeout
Expand All @@ -58,7 +58,7 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
await delay(interval_ms);
}

console.log("Waited " + timeWaited + " for ROS Core to start");
extension.outputChannel.appendLine("Waited " + timeWaited + " for ROS Core to start");

if (timeWaited >= timeout_ms) {
throw new Error('Timed out (' + timeWaited / 1000 + ' seconds) waiting for ROS Core to start. Start ROSCore manually to avoid this error.');
Expand Down
204 changes: 95 additions & 109 deletions src/debugger/configuration/resolvers/ros2/launch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import * as child_process from "child_process";
import * as fs from "fs";
import * as fsp from "fs/promises";
import * as yaml from "js-yaml";
import * as os from "os";
import * as path from "path";
Expand Down Expand Up @@ -32,25 +33,33 @@ interface ILaunchRequest {
attachDebugger?: string[]; // If specified, Scripts or executables to debug; otherwise attaches to everything not ignored
}

interface ICppEnvConfig {
name: string;
value: string;
}

function getExtensionFilePath(extensionFile: string): string {
return path.resolve(extension.extPath, extensionFile);
}

export class LaunchResolver implements vscode.DebugConfigurationProvider {
// tslint:disable-next-line: max-line-length
public async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: requests.ILaunchRequest, token?: vscode.CancellationToken) {
if (!path.isAbsolute(config.target)) {
throw new Error("Launch request requires an absolute path as target.");
await fsp.access(config.target, fs.constants.R_OK);

if (path.extname(config.target) == ".xml" || path.extname(config.target) == ".yaml") {
throw new Error("Support for '.xml' or '.yaml' launch files coming soon (see https://github.com/ms-iot/vscode-ros/issues/805).");
}
else if (path.extname(config.target) !== ".py" && path.extname(config.target) !== ".xml") {
throw new Error("Launch request requires an extension '.py' or '.xml' as target.");

if (path.extname(config.target) !== ".py") {
throw new Error("Launch request requires an extension '.py'.");
}

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

// Manage the status of the ROS2 Daemon, starting one if not present
if (await rosApi.getCoreStatus() == false) {
console.log("ROS Daemon is not active, attempting to start automatically");
extension.outputChannel.appendLine("ROS Daemon is not active, attempting to start automatically");
rosApi.startCore();

// Wait for the core to start up to a timeout
Expand All @@ -63,11 +72,7 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
await delay(interval_ms);
}

console.log("Waited " + timeWaited + " for ROS2 Daemon to start");

if (timeWaited >= timeout_ms) {
throw new Error('Timed out (' + timeWaited / 1000 + ' seconds) waiting for ROS2 Daemon to start. Start ROS2 Daemon manually to avoid this error.');
}
extension.outputChannel.appendLine("Waited " + timeWaited + " for ROS2 Daemon to start. Proceeding without the Daemon.");
}

const rosExecOptions: child_process.ExecOptions = {
Expand All @@ -77,8 +82,8 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
},
};

console.log("Executing dumper with the following environment:");
console.log(rosExecOptions.env);
extension.outputChannel.appendLine("Executing dumper with the following environment:");
extension.outputChannel.appendLine(JSON.stringify(rosExecOptions.env));

let ros2_launch_dumper = getExtensionFilePath(path.join("assets", "scripts", "ros2_launch_dumper.py"));

Expand All @@ -97,7 +102,7 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {

if (result.stderr) {
// Having stderr output is not nessesarily a problem, but it is useful for debugging
console.log(`ROS2 launch processor produced stderr output:\r\n ${result.stderr}`);
extension.outputChannel.appendLine(`ROS2 launch processor produced stderr output:\r\n ${result.stderr}`);
}

if (result.stdout.length == 0) {
Expand Down Expand Up @@ -188,50 +193,84 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
return null;
}

private createPythonLaunchConfig(request: ILaunchRequest, stopOnEntry: boolean): IPythonLaunchConfiguration {
const pythonLaunchConfig: IPythonLaunchConfiguration = {
name: request.nodeName,
type: "python",
request: "launch",
program: request.executable,
args: request.arguments,
env: request.env,
stopOnEntry: stopOnEntry,
justMyCode: false,
};

return pythonLaunchConfig;
}

private createCppLaunchConfig(request: ILaunchRequest, stopOnEntry: boolean): ICppvsdbgLaunchConfiguration {
const envConfigs: ICppEnvConfig[] = [];
for (const key in request.env) {
if (request.env.hasOwnProperty(key)) {
envConfigs.push({
name: key,
value: request.env[key],
});
}
}

const cppvsdbgLaunchConfig: ICppvsdbgLaunchConfiguration = {
name: request.nodeName,
type: "cppvsdbg",
request: "launch",
cwd: ".",
program: request.executable,
args: request.arguments,
environment: envConfigs,
stopAtEntry: stopOnEntry,
symbolSearchPath: request.symbolSearchPath,
sourceFileMap: request.sourceFileMap

};

return cppvsdbgLaunchConfig;
}

private async executeLaunchRequest(request: ILaunchRequest, stopOnEntry: boolean) {
let debugConfig: ICppvsdbgLaunchConfiguration | ICppdbgLaunchConfiguration | IPythonLaunchConfiguration;

if (os.platform() === "win32") {
if (request.executable.toLowerCase().endsWith(".py")) {
const pythonLaunchConfig: IPythonLaunchConfiguration = {
name: request.nodeName,
type: "python",
request: "launch",
program: request.executable,
args: request.arguments,
env: request.env,
stopOnEntry: stopOnEntry,
justMyCode: false,
};
debugConfig = pythonLaunchConfig;
} else if (request.executable.toLowerCase().endsWith(".exe")) {
interface ICppEnvConfig {
name: string;
value: string;
}
const envConfigs: ICppEnvConfig[] = [];
for (const key in request.env) {
if (request.env.hasOwnProperty(key)) {
envConfigs.push({
name: key,
value: request.env[key],
});
}
let nodePath = path.parse(request.executable);

if (nodePath.ext.toLowerCase() === ".exe") {

// On Windows, colcon will compile Python scripts, C# and Rust programs to .exe.
// Discriminate between different runtimes by introspection.

// Python
// rosnode.py will be compiled into install\rosnode\Lib\rosnode\rosnode.exe
// rosnode.py will also be copied into install\rosnode\Lib\site-packages\rosnode.py

let pythonPath = path.join(nodePath.dir, "..", "site-packages", nodePath.name, nodePath.name + ".py");

try {
await fsp.access(pythonPath, fs.constants.R_OK);

// If the python file is available, then treat it as python and fall through.
request.executable = pythonPath;
debugConfig = this.createPythonLaunchConfig(request, stopOnEntry);
} catch {
// The python file is not available then this must be...

// C#? Todo

// Rust? Todo

// C++
debugConfig = this.createCppLaunchConfig(request, stopOnEntry);
}
const cppvsdbgLaunchConfig: ICppvsdbgLaunchConfiguration = {
name: request.nodeName,
type: "cppvsdbg",
request: "launch",
cwd: ".",
program: request.executable,
args: request.arguments,
environment: envConfigs,
stopAtEntry: stopOnEntry,
symbolSearchPath: request.symbolSearchPath,
sourceFileMap: request.sourceFileMap

};
debugConfig = cppvsdbgLaunchConfig;
} else if (nodePath.ext.toLowerCase() === ".py") {
debugConfig = this.createPythonLaunchConfig(request, stopOnEntry);
}

if (!debugConfig) {
Expand All @@ -242,19 +281,8 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {
throw (new Error(`Failed to start debug session!`));
}
} else {
try {
// this should be guaranteed by roslaunch
fs.accessSync(request.executable, fs.constants.X_OK);
} catch (errNotExecutable) {
throw (new Error(`Error! ${request.executable} is not executable!`));
}

try {
// need to be readable to check shebang line
fs.accessSync(request.executable, fs.constants.R_OK);
} catch (errNotReadable) {
throw (new Error(`Error! ${request.executable} is not readable!`));
}
// this should be guaranteed by roslaunch
await fsp.access(request.executable, fs.constants.X_OK | fs.constants.R_OK);

const fileStream = fs.createReadStream(request.executable);
const rl = readline.createInterface({
Expand All @@ -275,51 +303,9 @@ export class LaunchResolver implements vscode.DebugConfigurationProvider {

// look for Python in shebang line
if (line.startsWith("#!") && line.toLowerCase().indexOf("python") !== -1) {
const pythonLaunchConfig: IPythonLaunchConfiguration = {
name: request.nodeName,
type: "python",
request: "launch",
program: request.executable,
args: request.arguments,
env: request.env,
stopOnEntry: stopOnEntry,
justMyCode: false,
};
debugConfig = pythonLaunchConfig;
debugConfig = this.createPythonLaunchConfig(request, stopOnEntry);
} else {
interface ICppEnvConfig {
name: string;
value: string;
}
const envConfigs: ICppEnvConfig[] = [];
for (const key in request.env) {
if (request.env.hasOwnProperty(key)) {
envConfigs.push({
name: key,
value: request.env[key],
});
}
}
const cppdbgLaunchConfig: ICppdbgLaunchConfiguration = {
name: request.nodeName,
type: "cppdbg",
request: "launch",
cwd: ".",
program: request.executable,
args: request.arguments,
environment: envConfigs,
stopAtEntry: stopOnEntry,
additionalSOLibSearchPath: request.additionalSOLibSearchPath,
sourceFileMap: request.sourceFileMap,
setupCommands: [
{
text: "-enable-pretty-printing",
description: "Enable pretty-printing for gdb",
ignoreFailures: true
}
]
};
debugConfig = cppdbgLaunchConfig;
debugConfig = this.createCppLaunchConfig(request, stopOnEntry);
}

if (!debugConfig) {
Expand Down
Loading