import { PsProcessParser } from './nativeAttach' ; import { AttachItem , showQuickPick } from './attachQuickPick' ; import { CppSettings } from '../LanguageServer/settings' ; import * as debugUtils from './utils' ; import * as os from 'os' ; import * as path from 'path' ; import * as util from '../common' ; import * as vscode from 'vscode' ; import * as nls from 'vscode-nls' ; nls . config ( { messageFormat : nls . MessageFormat . bundle , bundleFormat : nls . BundleFormat . standalone } ) ( ) ; const localize = nls . loadMessageBundle ( ) ; export interface AttachItemsProvider { getAttachItems ( ) : Promise < AttachItem [ ] > ; } export class AttachPicker { constructor ( private attachItemsProvider ) { } public async ShowAttachEntries ( ) { return showQuickPick ( ( ) => this . attachItemsProvider . getAttachItems ( ) ) ; } } export class RemoteAttachPicker { constructor ( ) { this . _channel = vscode . window . createOutputChannel ( 'remote-attach' ) ; } private _channel : vscode . OutputChannel ; public async ShowAttachEntries ( config ) { this . _channel . clear ( ) ; const pipeTransport = config ? config . pipeTransport : undefined ; if ( ! pipeTransport ) { throw new Error ( localize ( "no.pipetransport" , "Chosen debug configuration does not contain {0}" , "pipeTransport" ) ) ; } let pipeProgram ; if ( os . platform ( ) === 'win32' && pipeTransport . pipeProgram && ! await util . checkFileExists ( pipeTransport . pipeProgram ) ) { const pipeProgramStr = pipeTransport . pipeProgram . toLowerCase ( ) . trim ( ) ; const expectedArch = debugUtils . ArchType [ process . arch as keyof typeof debugUtils . ArchType ] ; if ( ! await util . checkFileExists ( config . pipeTransport . pipeProgram ) ) { pipeProgram = debugUtils . ArchitectureReplacer . checkAndReplaceWSLPipeProgram ( pipeProgramStr , expectedArch ) ; } if ( ! pipeProgram && config . pipeTransport . pipeCwd ) { const pipeCwdStr = config . pipeTransport . pipeCwd . toLowerCase ( ) . trim ( ) ; const newPipeProgramStr = path . join ( pipeCwdStr , pipeProgramStr ) ; if ( ! await util . checkFileExists ( newPipeProgramStr ) ) { pipeProgram = debugUtils . ArchitectureReplacer . checkAndReplaceWSLPipeProgram ( newPipeProgramStr , expectedArch ) ; } } } if ( ! pipeProgram ) { pipeProgram = pipeTransport . pipeProgram ; } const pipeArgs = pipeTransport . pipeArgs ; const argList = RemoteAttachPicker . createArgumentList ( pipeArgs ) ; const pipeCmd = `"${ pipeProgram }" ${ argList }` ; const processes = await this . getRemoteOSAndProcesses ( pipeCmd ) ; const attachPickOptions = { matchOnDetail : true , matchOnDescription : true , placeHolder : localize ( "select.process.attach" , "Select the process to attach to" ) } ; const item = await vscode . window . showQuickPick ( processes , attachPickOptions ) ; if ( item ) { return item . id ; } else { throw new Error ( localize ( "process.not.selected" , "Process not selected." ) ) ; } } private getRemoteProcessCommand ( ) { let innerQuote = `'` ; let outerQuote = `"` ; let parameterBegin = `$(` ; let parameterEnd = `)` ; let escapedQuote = `\\\"` ; const settings = new CppSettings ( ) ; if ( settings . useBacktickCommandSubstitution ) { parameterBegin = `\`` ; parameterEnd = `\`` ; escapedQuote = `\"` ; } if ( os . platform ( ) !== "win32" ) { innerQuote = `"` ; outerQuote = `'` ; } return `${ outerQuote }sh -c ${ innerQuote }uname && if [ ${ parameterBegin }uname${ parameterEnd } = ${ escapedQuote }Linux${ escapedQuote } ] ; ` + `then ${ PsProcessParser . psLinuxCommand } ; elif [ ${ parameterBegin }uname${ parameterEnd } = ${ escapedQuote }Darwin${ escapedQuote } ] ; ` + `then ${ PsProcessParser . psDarwinCommand }; fi${ innerQuote }${ outerQuote }` ; } private async getRemoteOSAndProcesses ( pipeCmd ) { const execCommand = `${ pipeCmd } ${ this . getRemoteProcessCommand ( ) }` ; const output = await util . execChildProcess ( execCommand , undefined , this . _channel ) ; const lines = output . split ( /\r?\n/ ) ; if ( lines . length === 0 ) { throw new Error ( localize ( "pipe.failed" , "Pipe transport failed to get OS and processes." ) ) ; } else { const remoteOS = lines [ 0 ] . replace ( /[\r\n]+/g , '' ) ; if ( remoteOS !== "Linux" && remoteOS !== "Darwin" ) { throw new Error ( `Operating system "${ remoteOS }" not supported.` ) ; } if ( lines . length === 1 ) { throw new Error ( localize ( "no.process.list" , "Transport attach could not obtain processes list." ) ) ; } else { const processes = lines . slice ( 1 ) ; return PsProcessParser . ParseProcessFromPsArray ( processes ) . sort ( ( a , b ) => { if ( a . name === undefined ) { if ( b . name === undefined ) { return 0 ; } return 1 ; } if ( b . name === undefined ) { return - 1 ; } const aLower = a . name . toLowerCase ( ) ; const bLower = b . name . toLowerCase ( ) ; if ( aLower === bLower ) { return 0 ; } return aLower < bLower ? - 1 : 1 ; } ) . map ( p => p . toAttachItem ( ) ) ; } } } private static createArgumentList ( args ) { let argsString = "" ; for ( const arg of args ) { if ( argsString ) { argsString += " " ; } argsString += `"${ arg }"` ; } return argsString ; } }