@@ -4,6 +4,8 @@ import * as utils from './helpers/utils';
44import * as ins from "./treeView/inspector"
55import * as c from './treeView/common' ;
66import * as path from 'path' ;
7+ import * as fs from 'fs' ;
8+ import { execSync } from 'child_process' ;
79
810import { TopoViewerEditor } from './topoViewer/providers/topoViewerEditorWebUiFacade' ;
911import { setCurrentTopoViewer } from './commands/graph' ;
@@ -35,6 +37,8 @@ export const DOCKER_IMAGES_STATE_KEY = 'dockerImages';
3537
3638export const extensionVersion = vscode . extensions . getExtension ( 'srl-labs.vscode-containerlab' ) ?. packageJSON . version ;
3739
40+ export let containerlabBinaryPath : string = 'containerlab' ;
41+
3842
3943function extractLabName ( session : any , prefix : string ) : string | undefined {
4044 if ( typeof session . network === 'string' && session . network . startsWith ( 'clab-' ) ) {
@@ -56,7 +60,7 @@ function extractLabName(session: any, prefix: string): string | undefined {
5660export async function refreshSshxSessions ( ) {
5761 try {
5862 const out = await utils . runWithSudo (
59- 'containerlab tools sshx list -f json' ,
63+ ` ${ containerlabBinaryPath } tools sshx list -f json` ,
6064 'List SSHX sessions' ,
6165 outputChannel ,
6266 'containerlab' ,
@@ -83,7 +87,7 @@ export async function refreshSshxSessions() {
8387export async function refreshGottySessions ( ) {
8488 try {
8589 const out = await utils . runWithSudo (
86- 'containerlab tools gotty list -f json' ,
90+ ` ${ containerlabBinaryPath } tools gotty list -f json` ,
8791 'List GoTTY sessions' ,
8892 outputChannel ,
8993 'containerlab' ,
@@ -382,6 +386,42 @@ function registerRealtimeUpdates(context: vscode.ExtensionContext) {
382386 ins . refreshFromEventStream ( ) ;
383387}
384388
389+ function setClabBinPath ( ) : boolean {
390+ const configPath = vscode . workspace . getConfiguration ( 'containerlab' ) . get < string > ( 'binaryPath' , '' ) ;
391+
392+ // if empty fall back to resolving from PATH
393+ if ( ! configPath || configPath . trim ( ) === '' ) {
394+ try {
395+ const stdout = execSync ( 'which containerlab' , { encoding : 'utf-8' } ) ;
396+ const resolvedPath = stdout . trim ( ) ;
397+ if ( resolvedPath ) {
398+ containerlabBinaryPath = resolvedPath ;
399+ outputChannel . info ( `Resolved containerlab binary from sys PATH as: ${ resolvedPath } ` ) ;
400+ return true ;
401+ }
402+ } catch ( err ) {
403+ outputChannel . warn ( 'Could not resolve containerlab bin path from sys PATH' ) ;
404+ }
405+ containerlabBinaryPath = 'containerlab' ;
406+ return true ;
407+ }
408+
409+ try {
410+ // Check if file exists and is executable
411+ fs . accessSync ( configPath , fs . constants . X_OK ) ;
412+ containerlabBinaryPath = configPath ;
413+ outputChannel . info ( `Using user configured containerlab binary: ${ configPath } ` ) ;
414+ return true ;
415+ } catch ( err ) {
416+ // Path is invalid or not executable - try to resolve from PATH as fallback
417+ outputChannel . error ( `Invalid containerlab.binaryPath setting: "${ configPath } " is not a valid executable.` ) ;
418+ vscode . window . showErrorMessage (
419+ `Configured containerlab binary path "${ configPath } " is invalid or not executable.`
420+ ) ;
421+ }
422+ return false ;
423+ }
424+
385425/**
386426 * Called when VSCode activates your extension.
387427 */
@@ -392,6 +432,12 @@ export async function activate(context: vscode.ExtensionContext) {
392432
393433 outputChannel . info ( process . platform ) ;
394434
435+ if ( ! setClabBinPath ( ) ) {
436+ // dont activate
437+ return ;
438+ }
439+
440+
395441 // Allow activation only on Linux or when connected via WSL.
396442 // Provide a more helpful message for macOS users with a workaround link.
397443 if ( process . platform !== "linux" && vscode . env . remoteName !== "wsl" ) {
0 commit comments